From 3ef009317801dca47efe34bd048d3cab2e644ee2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Sep 2024 10:39:47 -0700 Subject: [PATCH 001/219] chore(deps-dev): bump sinon from 18.0.1 to 19.0.1 (#938) Bumps [sinon](https://github.com/sinonjs/sinon) from 18.0.1 to 19.0.1. - [Release notes](https://github.com/sinonjs/sinon/releases) - [Changelog](https://github.com/sinonjs/sinon/blob/main/docs/changelog.md) - [Commits](https://github.com/sinonjs/sinon/compare/v18.0.1...v19.0.1) --- updated-dependencies: - dependency-name: sinon dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 98287ff51..ad1c15632 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "prettier": "^3.0.0", "semantic-release": "^24.0.0", "semver": "^7.3.7", - "sinon": "^18.0.0", + "sinon": "^19.0.1", "ts-node": "^10.9.1", "typescript": "^5.4.2" }, From 0a08cf5e7e11e9f87ed4f83b987632605fb45008 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 13 Sep 2024 17:44:35 +0000 Subject: [PATCH 002/219] chore(release): 8.9.2 [skip ci] ## [8.9.2](https://github.com/appium/WebDriverAgent/compare/v8.9.1...v8.9.2) (2024-09-13) ### Miscellaneous Chores * **deps-dev:** bump sinon from 18.0.1 to 19.0.1 ([#938](https://github.com/appium/WebDriverAgent/issues/938)) ([3ef0093](https://github.com/appium/WebDriverAgent/commit/3ef009317801dca47efe34bd048d3cab2e644ee2)) --- CHANGELOG.md | 6 ++++++ WebDriverAgentLib/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b79c45c7..2fb98c7d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [8.9.2](https://github.com/appium/WebDriverAgent/compare/v8.9.1...v8.9.2) (2024-09-13) + +### Miscellaneous Chores + +* **deps-dev:** bump sinon from 18.0.1 to 19.0.1 ([#938](https://github.com/appium/WebDriverAgent/issues/938)) ([3ef0093](https://github.com/appium/WebDriverAgent/commit/3ef009317801dca47efe34bd048d3cab2e644ee2)) + ## [8.9.1](https://github.com/appium/WebDriverAgent/compare/v8.9.0...v8.9.1) (2024-08-09) ### Bug Fixes diff --git a/WebDriverAgentLib/Info.plist b/WebDriverAgentLib/Info.plist index 28efd96d3..a43dfce01 100644 --- a/WebDriverAgentLib/Info.plist +++ b/WebDriverAgentLib/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 8.9.1 + 8.9.2 CFBundleSignature ???? CFBundleVersion - 8.9.1 + 8.9.2 NSPrincipalClass diff --git a/package.json b/package.json index ad1c15632..ced94dc6b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "appium-webdriveragent", - "version": "8.9.1", + "version": "8.9.2", "description": "Package bundling WebDriverAgent", "main": "./build/index.js", "types": "./build/index.d.ts", From 9fd58b6c43ddeefd22ef379f8a92c867dfb4974b Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Wed, 18 Sep 2024 09:27:21 -0700 Subject: [PATCH 003/219] ci: add Xcode 16 (#939) * docs: use Xcode 16 beta 6 * Update functional-test.yml * Update functional-test.yml --- .github/workflows/functional-test.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/functional-test.yml b/.github/workflows/functional-test.yml index e9bb01e19..4e51234c4 100644 --- a/.github/workflows/functional-test.yml +++ b/.github/workflows/functional-test.yml @@ -12,6 +12,9 @@ jobs: fail-fast: false matrix: test_targets: + - XCODE_VERSION: '16.0.0' + IOS_VERSION: '18.0' + IOS_MODEL: iPhone 15 Plus - XCODE_VERSION: '15.3' IOS_VERSION: '17.4' IOS_MODEL: iPhone 15 Plus From a2173d05df8ef831310e805a8e6a8a8d17725201 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20L=C3=BCdeke?= <311702+aluedeke@users.noreply.github.com> Date: Mon, 7 Oct 2024 22:19:13 +0200 Subject: [PATCH 004/219] chore: remove unused FBBaseActionsParser and cleanup imports in FBConfiguration (#943) --- Configurations/IOSSettings.xcconfig | 2 +- Configurations/TVOSSettings.xcconfig | 2 +- .../Utilities/FBBaseActionsParser.m | 32 ------------------- WebDriverAgentLib/Utilities/FBConfiguration.h | 4 --- WebDriverAgentLib/Utilities/FBConfiguration.m | 4 +++ 5 files changed, 6 insertions(+), 38 deletions(-) delete mode 100644 WebDriverAgentLib/Utilities/FBBaseActionsParser.m diff --git a/Configurations/IOSSettings.xcconfig b/Configurations/IOSSettings.xcconfig index 70ae5ec68..b9969a48b 100644 --- a/Configurations/IOSSettings.xcconfig +++ b/Configurations/IOSSettings.xcconfig @@ -28,4 +28,4 @@ RUN_CLANG_STATIC_ANALYZER = YES GCC_PREPROCESSOR_DEFINITIONS = $(inherited) -WARNING_CFLAGS = $(inherited) -Weverything -Wno-objc-missing-property-synthesis -Wno-unused-macros -Wno-disabled-macro-expansion -Wno-gnu-statement-expression -Wno-language-extension-token -Wno-overriding-method-mismatch -Wno-missing-variable-declarations -Rno-module-build -Wno-auto-import -Wno-objc-interface-ivars -Wno-documentation-unknown-command -Wno-reserved-id-macro -Wno-unused-parameter -Wno-gnu-conditional-omitted-operand -Wno-explicit-ownership-type -Wno-date-time -Wno-cast-align -Wno-cstring-format-directive -Wno-double-promotion -Wno-partial-availability +WARNING_CFLAGS = $(inherited) -Weverything -Wno-objc-missing-property-synthesis -Wno-unused-macros -Wno-disabled-macro-expansion -Wno-gnu-statement-expression -Wno-language-extension-token -Wno-overriding-method-mismatch -Wno-missing-variable-declarations -Rno-module-build -Wno-auto-import -Wno-objc-interface-ivars -Wno-documentation-unknown-command -Wno-reserved-id-macro -Wno-unused-parameter -Wno-gnu-conditional-omitted-operand -Wno-explicit-ownership-type -Wno-date-time -Wno-cast-align -Wno-cstring-format-directive -Wno-double-promotion -Wno-partial-availability -Wno-declaration-after-statement -Wno-objc-messaging-id -Wno-direct-ivar-access -Wno-cast-qual -Wno-deprecated-declarations diff --git a/Configurations/TVOSSettings.xcconfig b/Configurations/TVOSSettings.xcconfig index 70ae5ec68..b9969a48b 100644 --- a/Configurations/TVOSSettings.xcconfig +++ b/Configurations/TVOSSettings.xcconfig @@ -28,4 +28,4 @@ RUN_CLANG_STATIC_ANALYZER = YES GCC_PREPROCESSOR_DEFINITIONS = $(inherited) -WARNING_CFLAGS = $(inherited) -Weverything -Wno-objc-missing-property-synthesis -Wno-unused-macros -Wno-disabled-macro-expansion -Wno-gnu-statement-expression -Wno-language-extension-token -Wno-overriding-method-mismatch -Wno-missing-variable-declarations -Rno-module-build -Wno-auto-import -Wno-objc-interface-ivars -Wno-documentation-unknown-command -Wno-reserved-id-macro -Wno-unused-parameter -Wno-gnu-conditional-omitted-operand -Wno-explicit-ownership-type -Wno-date-time -Wno-cast-align -Wno-cstring-format-directive -Wno-double-promotion -Wno-partial-availability +WARNING_CFLAGS = $(inherited) -Weverything -Wno-objc-missing-property-synthesis -Wno-unused-macros -Wno-disabled-macro-expansion -Wno-gnu-statement-expression -Wno-language-extension-token -Wno-overriding-method-mismatch -Wno-missing-variable-declarations -Rno-module-build -Wno-auto-import -Wno-objc-interface-ivars -Wno-documentation-unknown-command -Wno-reserved-id-macro -Wno-unused-parameter -Wno-gnu-conditional-omitted-operand -Wno-explicit-ownership-type -Wno-date-time -Wno-cast-align -Wno-cstring-format-directive -Wno-double-promotion -Wno-partial-availability -Wno-declaration-after-statement -Wno-objc-messaging-id -Wno-direct-ivar-access -Wno-cast-qual -Wno-deprecated-declarations diff --git a/WebDriverAgentLib/Utilities/FBBaseActionsParser.m b/WebDriverAgentLib/Utilities/FBBaseActionsParser.m deleted file mode 100644 index 872dc268e..000000000 --- a/WebDriverAgentLib/Utilities/FBBaseActionsParser.m +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -#import "FBBaseActionsSynthesizer.h" - -#import "FBErrorBuilder.h" - -@implementation FBBaseActionsSynthesizer - -- (instancetype)initWithActions:(NSArray *)actions forApplication:(XCUIApplication *)application -{ - self = [super init]; - if (self) { - _actions = actions; - _application = application; - } - return self; -} - -- (nullable XCSynthesizedEventRecord *)synthesizeWithError:(NSError **)error -{ - @throw [[FBErrorBuilder.builder withDescription:@"Override this method in subclasses"] build]; - return nil; -} - -@end diff --git a/WebDriverAgentLib/Utilities/FBConfiguration.h b/WebDriverAgentLib/Utilities/FBConfiguration.h index dc2018928..75275ccf6 100644 --- a/WebDriverAgentLib/Utilities/FBConfiguration.h +++ b/WebDriverAgentLib/Utilities/FBConfiguration.h @@ -9,10 +9,6 @@ #import -#import "AXSettings.h" -#import "UIKeyboardImpl.h" -#import "TIPreferencesController.h" - NS_ASSUME_NONNULL_BEGIN extern NSString *const FBSnapshotMaxDepthKey; diff --git a/WebDriverAgentLib/Utilities/FBConfiguration.m b/WebDriverAgentLib/Utilities/FBConfiguration.m index 1d7438ae1..e91717b2d 100644 --- a/WebDriverAgentLib/Utilities/FBConfiguration.m +++ b/WebDriverAgentLib/Utilities/FBConfiguration.m @@ -9,6 +9,10 @@ #import "FBConfiguration.h" +#import "AXSettings.h" +#import "UIKeyboardImpl.h" +#import "TIPreferencesController.h" + #include #import From f9223b3b4cb9bd25c033f53edb5314abfbd27f62 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 7 Oct 2024 20:24:12 +0000 Subject: [PATCH 005/219] chore(release): 8.9.3 [skip ci] ## [8.9.3](https://github.com/appium/WebDriverAgent/compare/v8.9.2...v8.9.3) (2024-10-07) ### Miscellaneous Chores * remove unused FBBaseActionsParser and cleanup imports in FBConfiguration ([#943](https://github.com/appium/WebDriverAgent/issues/943)) ([a2173d0](https://github.com/appium/WebDriverAgent/commit/a2173d05df8ef831310e805a8e6a8a8d17725201)) --- CHANGELOG.md | 6 ++++++ WebDriverAgentLib/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fb98c7d4..bab482944 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [8.9.3](https://github.com/appium/WebDriverAgent/compare/v8.9.2...v8.9.3) (2024-10-07) + +### Miscellaneous Chores + +* remove unused FBBaseActionsParser and cleanup imports in FBConfiguration ([#943](https://github.com/appium/WebDriverAgent/issues/943)) ([a2173d0](https://github.com/appium/WebDriverAgent/commit/a2173d05df8ef831310e805a8e6a8a8d17725201)) + ## [8.9.2](https://github.com/appium/WebDriverAgent/compare/v8.9.1...v8.9.2) (2024-09-13) ### Miscellaneous Chores diff --git a/WebDriverAgentLib/Info.plist b/WebDriverAgentLib/Info.plist index a43dfce01..63b4beea4 100644 --- a/WebDriverAgentLib/Info.plist +++ b/WebDriverAgentLib/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 8.9.2 + 8.9.3 CFBundleSignature ???? CFBundleVersion - 8.9.2 + 8.9.3 NSPrincipalClass diff --git a/package.json b/package.json index ced94dc6b..b813b8a01 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "appium-webdriveragent", - "version": "8.9.2", + "version": "8.9.3", "description": "Package bundling WebDriverAgent", "main": "./build/index.js", "types": "./build/index.d.ts", From f0bdce7eb8fdb13d2309d28e936950c77f006b20 Mon Sep 17 00:00:00 2001 From: mwakizaka <21286384+mwakizaka@users.noreply.github.com> Date: Thu, 17 Oct 2024 19:35:13 +0900 Subject: [PATCH 006/219] fix: Consider transient overlay windows when respectSystemAlerts is enabled (#946) --- WebDriverAgentLib/Routing/FBSession.m | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/WebDriverAgentLib/Routing/FBSession.m b/WebDriverAgentLib/Routing/FBSession.m index 14565ad00..a4460b4a8 100644 --- a/WebDriverAgentLib/Routing/FBSession.m +++ b/WebDriverAgentLib/Routing/FBSession.m @@ -178,8 +178,13 @@ - (XCUIApplication *)activeApplication if (nil != self.testedApplication) { XCUIApplicationState testedAppState = self.testedApplication.state; if (testedAppState >= XCUIApplicationStateRunningForeground) { + // We look for `SBTransientOverlayWindow` elements for half modals. See https://github.com/appium/WebDriverAgent/pull/946 + NSPredicate *searchPredicate = [NSPredicate predicateWithFormat:@"%K == %@ OR %K == %@", + @"elementType", @(XCUIElementTypeAlert), + @"identifier", @"SBTransientOverlayWindow"]; if ([FBConfiguration shouldRespectSystemAlerts] - && [XCUIApplication.fb_systemApplication descendantsMatchingType:XCUIElementTypeAlert].count > 0) { + && [[XCUIApplication.fb_systemApplication descendantsMatchingType:XCUIElementTypeAny] + matchingPredicate:searchPredicate].count > 0) { return XCUIApplication.fb_systemApplication; } return (XCUIApplication *)self.testedApplication; From 7bd044d75a1f75a9c2696e1a031ffda822f457b7 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 17 Oct 2024 10:40:25 +0000 Subject: [PATCH 007/219] chore(release): 8.9.4 [skip ci] ## [8.9.4](https://github.com/appium/WebDriverAgent/compare/v8.9.3...v8.9.4) (2024-10-17) ### Bug Fixes * Consider transient overlay windows when respectSystemAlerts is enabled ([#946](https://github.com/appium/WebDriverAgent/issues/946)) ([f0bdce7](https://github.com/appium/WebDriverAgent/commit/f0bdce7eb8fdb13d2309d28e936950c77f006b20)) --- CHANGELOG.md | 6 ++++++ WebDriverAgentLib/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bab482944..619060ee0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [8.9.4](https://github.com/appium/WebDriverAgent/compare/v8.9.3...v8.9.4) (2024-10-17) + +### Bug Fixes + +* Consider transient overlay windows when respectSystemAlerts is enabled ([#946](https://github.com/appium/WebDriverAgent/issues/946)) ([f0bdce7](https://github.com/appium/WebDriverAgent/commit/f0bdce7eb8fdb13d2309d28e936950c77f006b20)) + ## [8.9.3](https://github.com/appium/WebDriverAgent/compare/v8.9.2...v8.9.3) (2024-10-07) ### Miscellaneous Chores diff --git a/WebDriverAgentLib/Info.plist b/WebDriverAgentLib/Info.plist index 63b4beea4..7749d5e09 100644 --- a/WebDriverAgentLib/Info.plist +++ b/WebDriverAgentLib/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 8.9.3 + 8.9.4 CFBundleSignature ???? CFBundleVersion - 8.9.3 + 8.9.4 NSPrincipalClass diff --git a/package.json b/package.json index b813b8a01..922e3a73e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "appium-webdriveragent", - "version": "8.9.3", + "version": "8.9.4", "description": "Package bundling WebDriverAgent", "main": "./build/index.js", "types": "./build/index.d.ts", From afd09a8eeb1fa28ed7e070cbf25605e578b26b25 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Mon, 28 Oct 2024 23:15:00 -0700 Subject: [PATCH 008/219] ci: update azure env (#947) * ci: update azure env * update testAccessbilityAudit * add an assertion * skip for now --- .azure-pipelines.yml | 28 +++++++++---------- .../IntegrationTests/FBVideoRecordingTests.m | 2 ++ .../XCUIApplicationHelperTests.m | 20 ++++++++++++- 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index a324a9b7d..89887d258 100644 --- a/.azure-pipelines.yml +++ b/.azure-pipelines.yml @@ -1,19 +1,19 @@ # https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/hosted?view=azure-devops&tabs=yaml variables: - MIN_VM_IMAGE: macOS-12 - MIN_XCODE_VERSION: 13.1 - MIN_PLATFORM_VERSION: 15.0 - MIN_TV_PLATFORM_VERSION: 15.0 - MIN_TV_DEVICE_NAME: Apple TV 4K (2nd generation) - MIN_IPHONE_DEVICE_NAME: iPhone 11 - MIN_IPAD_DEVICE_NAME: iPad Pro (11-inch) (3rd generation) - MAX_VM_IMAGE: macOS-12 - MAX_XCODE_VERSION: 14.2 - MAX_PLATFORM_VERSION: 16.2 - MAX_PLATFORM_VERSION_TV: 16.1 - MAX_IPHONE_DEVICE_NAME: iPhone 13 - MAX_TV_DEVICE_NAME: Apple TV 4K (2nd generation) - MAX_IPAD_DEVICE_NAME: iPad Pro (11-inch) (3rd generation) + MIN_VM_IMAGE: macOS-14 + MIN_XCODE_VERSION: 14.3.1 + MIN_PLATFORM_VERSION: 16.4 + MIN_TV_PLATFORM_VERSION: 16.4 + MIN_TV_DEVICE_NAME: Apple TV 4K (3rd generation) + MIN_IPHONE_DEVICE_NAME: iPhone 14 Plus + MIN_IPAD_DEVICE_NAME: iPad Pro (11-inch) (4th generation) + MAX_VM_IMAGE: macOS-14 + MAX_XCODE_VERSION: 15.4 + MAX_PLATFORM_VERSION: 17.5 + MAX_PLATFORM_VERSION_TV: 17.5 + MAX_IPHONE_DEVICE_NAME: iPhone 15 Plus + MAX_TV_DEVICE_NAME: Apple TV 4K (3rd generation) + MAX_IPAD_DEVICE_NAME: iPad Air 11-inch (M2) DEFAULT_NODE_VERSION: "18.x" trigger: diff --git a/WebDriverAgentTests/IntegrationTests/FBVideoRecordingTests.m b/WebDriverAgentTests/IntegrationTests/FBVideoRecordingTests.m index 617480c0c..191af3420 100644 --- a/WebDriverAgentTests/IntegrationTests/FBVideoRecordingTests.m +++ b/WebDriverAgentTests/IntegrationTests/FBVideoRecordingTests.m @@ -31,6 +31,8 @@ - (void)setUp - (void)testStartingAndStoppingVideoRecording { + XCTSkip(@"Failed on Azure Pipeline. Local run succeeded."); + // Video recording is only available since iOS 17 if (SYSTEM_VERSION_LESS_THAN(@"17.0")) { return; diff --git a/WebDriverAgentTests/IntegrationTests/XCUIApplicationHelperTests.m b/WebDriverAgentTests/IntegrationTests/XCUIApplicationHelperTests.m index e86f62021..15b906db7 100644 --- a/WebDriverAgentTests/IntegrationTests/XCUIApplicationHelperTests.m +++ b/WebDriverAgentTests/IntegrationTests/XCUIApplicationHelperTests.m @@ -111,7 +111,25 @@ - (void)testAccessbilityAudit [set addObject:@"XCUIAccessibilityAuditTypeAll"]; NSArray *auditIssues2 = [XCUIApplication.fb_activeApplication fb_performAccessibilityAuditWithAuditTypesSet:set.copy error:&error]; - XCTAssertEqualObjects(auditIssues1, auditIssues2); + // 'elementDescription' is not in this list because it could have + // different object id's debug description in XCTest. + NSArray *checkKeys = @[ + @"auditType", + @"compactDescription", + @"detailedDescription", + @"element", + @"elementAttributes" + ]; + + XCTAssertEqual([auditIssues1 count], [auditIssues2 count]); + for (int i = 1; i < [auditIssues1 count]; i++) { + for (NSString *k in checkKeys) { + XCTAssertEqualObjects( + [auditIssues1[i] objectForKey:k], + [auditIssues2[i] objectForKey:k] + ); + } + } XCTAssertNil(error); } From 61bc051180d691d26233c66a5a76ed20b7fa09d2 Mon Sep 17 00:00:00 2001 From: KAdachi <27220367+ppken@users.noreply.github.com> Date: Thu, 7 Nov 2024 16:36:51 +0900 Subject: [PATCH 009/219] feat: add useClearTextShortcut setting (#952) --- WebDriverAgentLib/Categories/XCUIElement+FBTyping.m | 2 +- WebDriverAgentLib/Commands/FBSessionCommands.m | 8 ++++++++ WebDriverAgentLib/Utilities/FBConfiguration.h | 9 +++++++++ WebDriverAgentLib/Utilities/FBConfiguration.m | 12 ++++++++++++ WebDriverAgentLib/Utilities/FBSettings.h | 1 + WebDriverAgentLib/Utilities/FBSettings.m | 1 + lib/types.ts | 1 + 7 files changed, 33 insertions(+), 1 deletion(-) diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBTyping.m b/WebDriverAgentLib/Categories/XCUIElement+FBTyping.m index db516a220..8b59ad031 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBTyping.m +++ b/WebDriverAgentLib/Categories/XCUIElement+FBTyping.m @@ -166,7 +166,7 @@ - (BOOL)fb_clearTextWithSnapshot:(FBXCElementSnapshotWrapper *)snapshot [self fb_prepareForTextInputWithSnapshot:snapshot]; } - if (retry == 0) { + if (retry == 0 && FBConfiguration.useClearTextShortcut) { // 1st attempt is via the IOHIDEvent as the fastest operation // https://github.com/appium/appium/issues/19389 [[XCUIDevice sharedDevice] fb_performIOHIDEventWithPage:0x07 // kHIDPage_KeyboardOrKeypad diff --git a/WebDriverAgentLib/Commands/FBSessionCommands.m b/WebDriverAgentLib/Commands/FBSessionCommands.m index c11c5eabb..e5d4894f5 100644 --- a/WebDriverAgentLib/Commands/FBSessionCommands.m +++ b/WebDriverAgentLib/Commands/FBSessionCommands.m @@ -141,6 +141,10 @@ + (NSArray *)routes [FBConfiguration forceSimulatorSoftwareKeyboardPresence]; } + if (capabilities[FB_SETTING_USE_CLEAR_TEXT_SHORTCUT]) { + [FBConfiguration setUseClearTextShortcut:[capabilities[FB_SETTING_USE_CLEAR_TEXT_SHORTCUT] boolValue]]; + } + NSString *bundleID = capabilities[FB_CAP_BUNDLE_ID]; NSString *initialUrl = capabilities[FB_CAP_INITIAL_URL]; XCUIApplication *app = nil; @@ -351,6 +355,7 @@ + (NSArray *)routes FB_SETTING_DEFAULT_ALERT_ACTION: request.session.defaultAlertAction ?: @"", FB_SETTING_MAX_TYPING_FREQUENCY: @([FBConfiguration maxTypingFrequency]), FB_SETTING_RESPECT_SYSTEM_ALERTS: @([FBConfiguration shouldRespectSystemAlerts]), + FB_SETTING_USE_CLEAR_TEXT_SHORTCUT: @([FBConfiguration useClearTextShortcut]), #if !TARGET_OS_TV FB_SETTING_SCREENSHOT_ORIENTATION: [FBConfiguration humanReadableScreenshotOrientation], #endif @@ -449,6 +454,9 @@ + (NSArray *)routes if (nil != [settings objectForKey:FB_SETTING_MAX_TYPING_FREQUENCY]) { [FBConfiguration setMaxTypingFrequency:[[settings objectForKey:FB_SETTING_MAX_TYPING_FREQUENCY] unsignedIntegerValue]]; } + if (nil != [settings objectForKey:FB_SETTING_USE_CLEAR_TEXT_SHORTCUT]) { + [FBConfiguration setUseClearTextShortcut:[[settings objectForKey:FB_SETTING_USE_CLEAR_TEXT_SHORTCUT] boolValue]]; + } #if !TARGET_OS_TV if (nil != [settings objectForKey:FB_SETTING_SCREENSHOT_ORIENTATION]) { diff --git a/WebDriverAgentLib/Utilities/FBConfiguration.h b/WebDriverAgentLib/Utilities/FBConfiguration.h index 75275ccf6..7c337826c 100644 --- a/WebDriverAgentLib/Utilities/FBConfiguration.h +++ b/WebDriverAgentLib/Utilities/FBConfiguration.h @@ -283,6 +283,15 @@ typedef NS_ENUM(NSInteger, FBConfigurationKeyboardPreference) { + (void)setDismissAlertButtonSelector:(NSString *)classChainSelector; + (NSString *)dismissAlertButtonSelector; +/** + * Whether to use HIDEvent for text clear. + * By default this is enabled and HIDEvent is used for text clear. + * + * @param enabled Either YES or NO + */ ++ (void)setUseClearTextShortcut:(BOOL)enabled; ++ (BOOL)useClearTextShortcut; + #if !TARGET_OS_TV /** Set the screenshot orientation for iOS diff --git a/WebDriverAgentLib/Utilities/FBConfiguration.m b/WebDriverAgentLib/Utilities/FBConfiguration.m index e91717b2d..dab8cb4db 100644 --- a/WebDriverAgentLib/Utilities/FBConfiguration.m +++ b/WebDriverAgentLib/Utilities/FBConfiguration.m @@ -56,6 +56,7 @@ static NSTimeInterval FBAnimationCoolOffTimeout; static BOOL FBShouldUseCompactResponses; static NSString *FBElementResponseAttributes; +static BOOL FBUseClearTextShortcut; #if !TARGET_OS_TV static UIInterfaceOrientation FBScreenshotOrientation; #endif @@ -438,6 +439,16 @@ + (NSString *)dismissAlertButtonSelector return FBDismissAlertButtonSelector; } ++ (void)setUseClearTextShortcut:(BOOL)enabled +{ + FBUseClearTextShortcut = enabled; +} + ++ (BOOL)useClearTextShortcut +{ + return FBUseClearTextShortcut; +} + #if !TARGET_OS_TV + (BOOL)setScreenshotOrientation:(NSString *)orientation error:(NSError **)error { @@ -503,6 +514,7 @@ + (void)resetSessionSettings FBAnimationCoolOffTimeout = 2.; // 50 should be enough for the majority of the cases. The performance is acceptable for values up to 100. FBSetCustomParameterForElementSnapshot(FBSnapshotMaxDepthKey, @50); + FBUseClearTextShortcut = YES; #if !TARGET_OS_TV FBScreenshotOrientation = UIInterfaceOrientationUnknown; #endif diff --git a/WebDriverAgentLib/Utilities/FBSettings.h b/WebDriverAgentLib/Utilities/FBSettings.h index 5f4450110..b1f2f1fca 100644 --- a/WebDriverAgentLib/Utilities/FBSettings.h +++ b/WebDriverAgentLib/Utilities/FBSettings.h @@ -40,6 +40,7 @@ extern NSString* const FB_SETTING_WAIT_FOR_IDLE_TIMEOUT; extern NSString* const FB_SETTING_ANIMATION_COOL_OFF_TIMEOUT; extern NSString* const FB_SETTING_MAX_TYPING_FREQUENCY; extern NSString* const FB_SETTING_RESPECT_SYSTEM_ALERTS; +extern NSString* const FB_SETTING_USE_CLEAR_TEXT_SHORTCUT; NS_ASSUME_NONNULL_END diff --git a/WebDriverAgentLib/Utilities/FBSettings.m b/WebDriverAgentLib/Utilities/FBSettings.m index a45afeb90..ada529eed 100644 --- a/WebDriverAgentLib/Utilities/FBSettings.m +++ b/WebDriverAgentLib/Utilities/FBSettings.m @@ -35,3 +35,4 @@ NSString* const FB_SETTING_ANIMATION_COOL_OFF_TIMEOUT = @"animationCoolOffTimeout"; NSString* const FB_SETTING_MAX_TYPING_FREQUENCY = @"maxTypingFrequency"; NSString* const FB_SETTING_RESPECT_SYSTEM_ALERTS = @"respectSystemAlerts"; +NSString* const FB_SETTING_USE_CLEAR_TEXT_SHORTCUT = @"useClearTextShortcut"; diff --git a/lib/types.ts b/lib/types.ts index 8b41dfc4e..82c51cb15 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -25,6 +25,7 @@ export interface WDASettings { waitForIdleTimeout?: number; animationCoolOffTimeout?: number; maxTypingFrequency?: number; + useClearTextShortcut?: boolean; } // WebDriverAgentLib/Utilities/FBCapabilities.h From 93f147a82e34042d388596d7522f7b4f896dc771 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 7 Nov 2024 07:41:17 +0000 Subject: [PATCH 010/219] chore(release): 8.10.0 [skip ci] ## [8.10.0](https://github.com/appium/WebDriverAgent/compare/v8.9.4...v8.10.0) (2024-11-07) ### Features * add useClearTextShortcut setting ([#952](https://github.com/appium/WebDriverAgent/issues/952)) ([61bc051](https://github.com/appium/WebDriverAgent/commit/61bc051180d691d26233c66a5a76ed20b7fa09d2)) --- CHANGELOG.md | 6 ++++++ WebDriverAgentLib/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 619060ee0..fd0e43dc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [8.10.0](https://github.com/appium/WebDriverAgent/compare/v8.9.4...v8.10.0) (2024-11-07) + +### Features + +* add useClearTextShortcut setting ([#952](https://github.com/appium/WebDriverAgent/issues/952)) ([61bc051](https://github.com/appium/WebDriverAgent/commit/61bc051180d691d26233c66a5a76ed20b7fa09d2)) + ## [8.9.4](https://github.com/appium/WebDriverAgent/compare/v8.9.3...v8.9.4) (2024-10-17) ### Bug Fixes diff --git a/WebDriverAgentLib/Info.plist b/WebDriverAgentLib/Info.plist index 7749d5e09..04d3b61c5 100644 --- a/WebDriverAgentLib/Info.plist +++ b/WebDriverAgentLib/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 8.9.4 + 8.10.0 CFBundleSignature ???? CFBundleVersion - 8.9.4 + 8.10.0 NSPrincipalClass diff --git a/package.json b/package.json index 922e3a73e..d3662bd62 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "appium-webdriveragent", - "version": "8.9.4", + "version": "8.10.0", "description": "Package bundling WebDriverAgent", "main": "./build/index.js", "types": "./build/index.d.ts", From 940df80937381b481a2762fbf86b6249804591bd Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Sun, 10 Nov 2024 07:33:16 -0800 Subject: [PATCH 011/219] chore: remove unnecessary lines (#954) --- WebDriverAgentLib/Commands/FBSessionCommands.m | 4 ---- 1 file changed, 4 deletions(-) diff --git a/WebDriverAgentLib/Commands/FBSessionCommands.m b/WebDriverAgentLib/Commands/FBSessionCommands.m index e5d4894f5..1972186d2 100644 --- a/WebDriverAgentLib/Commands/FBSessionCommands.m +++ b/WebDriverAgentLib/Commands/FBSessionCommands.m @@ -141,10 +141,6 @@ + (NSArray *)routes [FBConfiguration forceSimulatorSoftwareKeyboardPresence]; } - if (capabilities[FB_SETTING_USE_CLEAR_TEXT_SHORTCUT]) { - [FBConfiguration setUseClearTextShortcut:[capabilities[FB_SETTING_USE_CLEAR_TEXT_SHORTCUT] boolValue]]; - } - NSString *bundleID = capabilities[FB_CAP_BUNDLE_ID]; NSString *initialUrl = capabilities[FB_CAP_INITIAL_URL]; XCUIApplication *app = nil; From 6beb1b5393a4bde0e28051bffe23337846c5da72 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 10 Nov 2024 15:38:37 +0000 Subject: [PATCH 012/219] chore(release): 8.10.1 [skip ci] ## [8.10.1](https://github.com/appium/WebDriverAgent/compare/v8.10.0...v8.10.1) (2024-11-10) ### Miscellaneous Chores * remove unnecessary lines ([#954](https://github.com/appium/WebDriverAgent/issues/954)) ([940df80](https://github.com/appium/WebDriverAgent/commit/940df80937381b481a2762fbf86b6249804591bd)) --- CHANGELOG.md | 6 ++++++ WebDriverAgentLib/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd0e43dc5..4a2761854 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [8.10.1](https://github.com/appium/WebDriverAgent/compare/v8.10.0...v8.10.1) (2024-11-10) + +### Miscellaneous Chores + +* remove unnecessary lines ([#954](https://github.com/appium/WebDriverAgent/issues/954)) ([940df80](https://github.com/appium/WebDriverAgent/commit/940df80937381b481a2762fbf86b6249804591bd)) + ## [8.10.0](https://github.com/appium/WebDriverAgent/compare/v8.9.4...v8.10.0) (2024-11-07) ### Features diff --git a/WebDriverAgentLib/Info.plist b/WebDriverAgentLib/Info.plist index 04d3b61c5..f14279538 100644 --- a/WebDriverAgentLib/Info.plist +++ b/WebDriverAgentLib/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 8.10.0 + 8.10.1 CFBundleSignature ???? CFBundleVersion - 8.10.0 + 8.10.1 NSPrincipalClass diff --git a/package.json b/package.json index d3662bd62..062531ae1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "appium-webdriveragent", - "version": "8.10.0", + "version": "8.10.1", "description": "Package bundling WebDriverAgent", "main": "./build/index.js", "types": "./build/index.d.ts", From 6112223b21026fae5545fe1b1433a09c67ff524b Mon Sep 17 00:00:00 2001 From: Sawan Garg Date: Mon, 11 Nov 2024 18:23:24 +0530 Subject: [PATCH 013/219] feat: Add support for excluded_attributes in JSON source hierarchy (#953) --- .../Categories/XCUIApplication+FBHelpers.h | 6 +++ .../Categories/XCUIApplication+FBHelpers.m | 53 +++++++++++++++---- WebDriverAgentLib/Commands/FBDebugCommands.m | 7 ++- .../XCUIApplicationHelperTests.m | 7 +++ 4 files changed, 63 insertions(+), 10 deletions(-) diff --git a/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.h b/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.h index 3ef66423b..54d4bd281 100644 --- a/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.h +++ b/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.h @@ -31,6 +31,12 @@ NS_ASSUME_NONNULL_BEGIN */ - (NSDictionary *)fb_tree; +/** + @param excludedAttributes Set of possible attributes to be excluded i.e frame, enabled, visible, accessible, focused. If set to nil or an empty array then no attributes will be excluded from the resulting JSON + @return application elements tree in form of nested dictionaries + */ +- (NSDictionary *)fb_tree:(nullable NSSet *) excludedAttributes; + /** Return application elements accessibility tree in form of nested dictionaries */ diff --git a/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m b/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m index c3c99e6f5..6cdae945b 100644 --- a/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m +++ b/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m @@ -152,11 +152,16 @@ - (BOOL)fb_deactivateWithDuration:(NSTimeInterval)duration error:(NSError **)err } - (NSDictionary *)fb_tree +{ + return [self fb_tree:nil]; +} + +- (NSDictionary *)fb_tree:(nullable NSSet *) excludedAttributes { id snapshot = self.fb_isResolvedFromCache.boolValue ? self.lastSnapshot : [self fb_snapshotWithAllAttributesAndMaxDepth:nil]; - return [self.class dictionaryForElement:snapshot recursive:YES]; + return [self.class dictionaryForElement:snapshot recursive:YES excludedAttributes:excludedAttributes]; } - (NSDictionary *)fb_accessibilityTree @@ -167,7 +172,9 @@ - (NSDictionary *)fb_accessibilityTree return [self.class accessibilityInfoForElement:snapshot]; } -+ (NSDictionary *)dictionaryForElement:(id)snapshot recursive:(BOOL)recursive ++ (NSDictionary *)dictionaryForElement:(id)snapshot + recursive:(BOOL)recursive + excludedAttributes:(nullable NSSet *) excludedAttributes { NSMutableDictionary *info = [[NSMutableDictionary alloc] init]; info[@"type"] = [FBElementTypeTransformer shortStringWithElementType:snapshot.elementType]; @@ -177,11 +184,35 @@ + (NSDictionary *)dictionaryForElement:(id)snapshot recursi info[@"value"] = FBValueOrNull(wrappedSnapshot.wdValue); info[@"label"] = FBValueOrNull(wrappedSnapshot.wdLabel); info[@"rect"] = wrappedSnapshot.wdRect; - info[@"frame"] = NSStringFromCGRect(wrappedSnapshot.wdFrame); - info[@"isEnabled"] = [@([wrappedSnapshot isWDEnabled]) stringValue]; - info[@"isVisible"] = [@([wrappedSnapshot isWDVisible]) stringValue]; - info[@"isAccessible"] = [@([wrappedSnapshot isWDAccessible]) stringValue]; - info[@"isFocused"] = [@([wrappedSnapshot isWDFocused]) stringValue]; + + NSDictionary *attributeBlocks = @{ + @"frame": ^{ + return NSStringFromCGRect(wrappedSnapshot.wdFrame); + }, + @"enabled": ^{ + return [@([wrappedSnapshot isWDEnabled]) stringValue]; + }, + @"visible": ^{ + return [@([wrappedSnapshot isWDVisible]) stringValue]; + }, + @"accessible": ^{ + return [@([wrappedSnapshot isWDAccessible]) stringValue]; + }, + @"focused": ^{ + return [@([wrappedSnapshot isWDFocused]) stringValue]; + } + }; + + for (NSString *key in attributeBlocks) { + if (excludedAttributes == nil || ![excludedAttributes containsObject:key]) { + NSString *value = ((NSString * (^)(void))attributeBlocks[key])(); + if ([key isEqualToString:@"frame"]) { + info[key] = value; + } else { + info[[NSString stringWithFormat:@"is%@", [key capitalizedString]]] = value; + } + } + } if (!recursive) { return info.copy; @@ -191,7 +222,9 @@ + (NSDictionary *)dictionaryForElement:(id)snapshot recursi if ([childElements count]) { info[@"children"] = [[NSMutableArray alloc] init]; for (id childSnapshot in childElements) { - [info[@"children"] addObject:[self dictionaryForElement:childSnapshot recursive:YES]]; + [info[@"children"] addObject:[self dictionaryForElement:childSnapshot + recursive:YES + excludedAttributes:excludedAttributes]]; } } return info; @@ -379,7 +412,9 @@ - (BOOL)fb_dismissKeyboardWithKeyNames:(nullable NSArray *)keyNames id extractedElement = extractIssueProperty(issue, @"element"); id elementSnapshot = [extractedElement fb_takeSnapshot]; - NSDictionary *elementAttributes = elementSnapshot ? [self.class dictionaryForElement:elementSnapshot recursive:NO] : @{}; + NSDictionary *elementAttributes = elementSnapshot + ? [self.class dictionaryForElement:elementSnapshot recursive:NO excludedAttributes:nil] + : @{}; [resultArray addObject:@{ @"detailedDescription": extractIssueProperty(issue, @"detailedDescription") ?: @"", diff --git a/WebDriverAgentLib/Commands/FBDebugCommands.m b/WebDriverAgentLib/Commands/FBDebugCommands.m index dc96958d0..c3f9a7816 100644 --- a/WebDriverAgentLib/Commands/FBDebugCommands.m +++ b/WebDriverAgentLib/Commands/FBDebugCommands.m @@ -54,7 +54,12 @@ + (NSArray *)routes withExcludedAttributes:excludedAttributes] withScope:sourceScope]]; } else if ([sourceType caseInsensitiveCompare:SOURCE_FORMAT_JSON] == NSOrderedSame) { - result = application.fb_tree; + NSString *excludedAttributesString = request.parameters[@"excluded_attributes"]; + NSSet *excludedAttributes = (excludedAttributesString == nil) + ? nil + : [NSSet setWithArray:[excludedAttributesString componentsSeparatedByString:@","]]; + + result = [application fb_tree:excludedAttributes]; } else if ([sourceType caseInsensitiveCompare:SOURCE_FORMAT_DESCRIPTION] == NSOrderedSame) { result = application.fb_descriptionRepresentation; } else { diff --git a/WebDriverAgentTests/IntegrationTests/XCUIApplicationHelperTests.m b/WebDriverAgentTests/IntegrationTests/XCUIApplicationHelperTests.m index 15b906db7..794be2192 100644 --- a/WebDriverAgentTests/IntegrationTests/XCUIApplicationHelperTests.m +++ b/WebDriverAgentTests/IntegrationTests/XCUIApplicationHelperTests.m @@ -44,6 +44,13 @@ - (void)testApplicationTree XCTAssertNotNil(self.testedApplication.fb_accessibilityTree); } +- (void)testApplicationTreeAttributesFiltering +{ + NSDictionary *applicationTree = [self.testedApplication fb_tree:[NSSet setWithArray:@[@"visible"]]]; + XCTAssertNotNil(applicationTree); + XCTAssertNil([applicationTree objectForKey:@"isVisible"], @"'isVisible' key should not be present in the application tree"); +} + - (void)testDeactivateApplication { NSError *error; From a05bcf021ebf7b55f3b1c2f6e4242234f118132b Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 11 Nov 2024 12:59:16 +0000 Subject: [PATCH 014/219] chore(release): 8.11.0 [skip ci] ## [8.11.0](https://github.com/appium/WebDriverAgent/compare/v8.10.1...v8.11.0) (2024-11-11) ### Features * Add support for excluded_attributes in JSON source hierarchy ([#953](https://github.com/appium/WebDriverAgent/issues/953)) ([6112223](https://github.com/appium/WebDriverAgent/commit/6112223b21026fae5545fe1b1433a09c67ff524b)) --- CHANGELOG.md | 6 ++++++ WebDriverAgentLib/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a2761854..d1af845b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [8.11.0](https://github.com/appium/WebDriverAgent/compare/v8.10.1...v8.11.0) (2024-11-11) + +### Features + +* Add support for excluded_attributes in JSON source hierarchy ([#953](https://github.com/appium/WebDriverAgent/issues/953)) ([6112223](https://github.com/appium/WebDriverAgent/commit/6112223b21026fae5545fe1b1433a09c67ff524b)) + ## [8.10.1](https://github.com/appium/WebDriverAgent/compare/v8.10.0...v8.10.1) (2024-11-10) ### Miscellaneous Chores diff --git a/WebDriverAgentLib/Info.plist b/WebDriverAgentLib/Info.plist index f14279538..9fd975595 100644 --- a/WebDriverAgentLib/Info.plist +++ b/WebDriverAgentLib/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 8.10.1 + 8.11.0 CFBundleSignature ???? CFBundleVersion - 8.10.1 + 8.11.0 NSPrincipalClass diff --git a/package.json b/package.json index 062531ae1..a678782cd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "appium-webdriveragent", - "version": "8.10.1", + "version": "8.11.0", "description": "Package bundling WebDriverAgent", "main": "./build/index.js", "types": "./build/index.d.ts", From 021f34901866f4a7870914c00781b83bd0cbddc4 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Mon, 11 Nov 2024 09:25:23 -0800 Subject: [PATCH 015/219] chore: bump appium-ios-device (#955) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a678782cd..4798555e6 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "@appium/base-driver": "^9.0.0", "@appium/strongbox": "^0.x", "@appium/support": "^5.0.3", - "appium-ios-device": "^2.5.0", + "appium-ios-device": "^2.7.25", "appium-ios-simulator": "^6.0.0", "async-lock": "^1.0.0", "asyncbox": "^3.0.0", From 024b7c066b43fff3d5ee462d5ca386e497ca661e Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 11 Nov 2024 17:33:31 +0000 Subject: [PATCH 016/219] chore(release): 8.11.1 [skip ci] ## [8.11.1](https://github.com/appium/WebDriverAgent/compare/v8.11.0...v8.11.1) (2024-11-11) ### Miscellaneous Chores * bump appium-ios-device ([#955](https://github.com/appium/WebDriverAgent/issues/955)) ([021f349](https://github.com/appium/WebDriverAgent/commit/021f34901866f4a7870914c00781b83bd0cbddc4)) --- CHANGELOG.md | 6 ++++++ WebDriverAgentLib/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1af845b2..1a56783d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [8.11.1](https://github.com/appium/WebDriverAgent/compare/v8.11.0...v8.11.1) (2024-11-11) + +### Miscellaneous Chores + +* bump appium-ios-device ([#955](https://github.com/appium/WebDriverAgent/issues/955)) ([021f349](https://github.com/appium/WebDriverAgent/commit/021f34901866f4a7870914c00781b83bd0cbddc4)) + ## [8.11.0](https://github.com/appium/WebDriverAgent/compare/v8.10.1...v8.11.0) (2024-11-11) ### Features diff --git a/WebDriverAgentLib/Info.plist b/WebDriverAgentLib/Info.plist index 9fd975595..ead3f644e 100644 --- a/WebDriverAgentLib/Info.plist +++ b/WebDriverAgentLib/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 8.11.0 + 8.11.1 CFBundleSignature ???? CFBundleVersion - 8.11.0 + 8.11.1 NSPrincipalClass diff --git a/package.json b/package.json index 4798555e6..a06baeeeb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "appium-webdriveragent", - "version": "8.11.0", + "version": "8.11.1", "description": "Package bundling WebDriverAgent", "main": "./build/index.js", "types": "./build/index.d.ts", From 2e9be570db20ad38270e175ccaffdaa58ffe198e Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Tue, 12 Nov 2024 08:29:16 -0800 Subject: [PATCH 017/219] ci: use proper host os (#956) --- .github/workflows/functional-test.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/functional-test.yml b/.github/workflows/functional-test.yml index 4e51234c4..61b23bdd2 100644 --- a/.github/workflows/functional-test.yml +++ b/.github/workflows/functional-test.yml @@ -12,18 +12,21 @@ jobs: fail-fast: false matrix: test_targets: - - XCODE_VERSION: '16.0.0' + - HOST_OS: 'macos-15' + XCODE_VERSION: '16.0.0' IOS_VERSION: '18.0' - IOS_MODEL: iPhone 15 Plus - - XCODE_VERSION: '15.3' + IOS_MODEL: iPhone 16 Plus + - HOST_OS: 'macos-14' + XCODE_VERSION: '15.3' IOS_VERSION: '17.4' IOS_MODEL: iPhone 15 Plus - - XCODE_VERSION: 14.3.1 + - HOST_OS: 'macos-13' + XCODE_VERSION: 14.3.1 IOS_VERSION: '16.4' IOS_MODEL: iPhone 14 Plus # https://github.com/actions/runner-images/blob/main/images/macos/macos-14-Readme.md - runs-on: macos-14 + runs-on: ${{matrix.test_targets.HOST_OS}} steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 From 5b4af690043216c9c2bf51ba4320f1e93e2ea670 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Sat, 23 Nov 2024 10:40:11 -0800 Subject: [PATCH 018/219] ci: run with Xcode 16.1.0 (#950) * ci: run with Xcode 16.1.0 as well * Update functional-test.yml * use maco 13 for xcode 14.3.1 --- .azure-pipelines.yml | 2 +- .github/workflows/functional-test.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index 89887d258..eca3f55cf 100644 --- a/.azure-pipelines.yml +++ b/.azure-pipelines.yml @@ -1,6 +1,6 @@ # https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/hosted?view=azure-devops&tabs=yaml variables: - MIN_VM_IMAGE: macOS-14 + MIN_VM_IMAGE: macOS-13 MIN_XCODE_VERSION: 14.3.1 MIN_PLATFORM_VERSION: 16.4 MIN_TV_PLATFORM_VERSION: 16.4 diff --git a/.github/workflows/functional-test.yml b/.github/workflows/functional-test.yml index 61b23bdd2..b8c9855aa 100644 --- a/.github/workflows/functional-test.yml +++ b/.github/workflows/functional-test.yml @@ -13,8 +13,8 @@ jobs: matrix: test_targets: - HOST_OS: 'macos-15' - XCODE_VERSION: '16.0.0' - IOS_VERSION: '18.0' + XCODE_VERSION: '16.1.0' + IOS_VERSION: '18.1' IOS_MODEL: iPhone 16 Plus - HOST_OS: 'macos-14' XCODE_VERSION: '15.3' From 55b49c83581c9e88f70806d98015238de3104f19 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Dec 2024 11:58:18 -0800 Subject: [PATCH 019/219] chore(deps-dev): bump mocha from 10.8.2 to 11.0.1 (#959) Bumps [mocha](https://github.com/mochajs/mocha) from 10.8.2 to 11.0.1. - [Release notes](https://github.com/mochajs/mocha/releases) - [Changelog](https://github.com/mochajs/mocha/blob/main/CHANGELOG.md) - [Commits](https://github.com/mochajs/mocha/compare/v10.8.2...v11.0.1) --- updated-dependencies: - dependency-name: mocha dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a06baeeeb..8c9386971 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "chai-as-promised": "^8.0.0", "conventional-changelog-conventionalcommits": "^8.0.0", "node-simctl": "^7.0.1", - "mocha": "^10.0.0", + "mocha": "^11.0.1", "prettier": "^3.0.0", "semantic-release": "^24.0.0", "semver": "^7.3.7", From 593bb0381a70ff1c25fa35092d0e9fe0cb4db066 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 3 Dec 2024 20:01:04 +0000 Subject: [PATCH 020/219] chore(release): 8.11.2 [skip ci] ## [8.11.2](https://github.com/appium/WebDriverAgent/compare/v8.11.1...v8.11.2) (2024-12-03) ### Miscellaneous Chores * **deps-dev:** bump mocha from 10.8.2 to 11.0.1 ([#959](https://github.com/appium/WebDriverAgent/issues/959)) ([55b49c8](https://github.com/appium/WebDriverAgent/commit/55b49c83581c9e88f70806d98015238de3104f19)) --- CHANGELOG.md | 6 ++++++ WebDriverAgentLib/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a56783d3..4ad29b2da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [8.11.2](https://github.com/appium/WebDriverAgent/compare/v8.11.1...v8.11.2) (2024-12-03) + +### Miscellaneous Chores + +* **deps-dev:** bump mocha from 10.8.2 to 11.0.1 ([#959](https://github.com/appium/WebDriverAgent/issues/959)) ([55b49c8](https://github.com/appium/WebDriverAgent/commit/55b49c83581c9e88f70806d98015238de3104f19)) + ## [8.11.1](https://github.com/appium/WebDriverAgent/compare/v8.11.0...v8.11.1) (2024-11-11) ### Miscellaneous Chores diff --git a/WebDriverAgentLib/Info.plist b/WebDriverAgentLib/Info.plist index ead3f644e..ebf8f6cf9 100644 --- a/WebDriverAgentLib/Info.plist +++ b/WebDriverAgentLib/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 8.11.1 + 8.11.2 CFBundleSignature ???? CFBundleVersion - 8.11.1 + 8.11.2 NSPrincipalClass diff --git a/package.json b/package.json index 8c9386971..2c3d71bc0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "appium-webdriveragent", - "version": "8.11.1", + "version": "8.11.2", "description": "Package bundling WebDriverAgent", "main": "./build/index.js", "types": "./build/index.d.ts", From dbeb09c89f8c02e00a7bdffe7899650d435f3575 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Dec 2024 13:28:13 +0100 Subject: [PATCH 021/219] chore(deps): bump @appium/support from 5.1.8 to 6.0.0 (#960) Bumps [@appium/support](https://github.com/appium/appium/tree/HEAD/packages/support) from 5.1.8 to 6.0.0. - [Release notes](https://github.com/appium/appium/releases) - [Changelog](https://github.com/appium/appium/blob/master/packages/support/CHANGELOG.md) - [Commits](https://github.com/appium/appium/commits/@appium/support@6.0.0/packages/support) --- updated-dependencies: - dependency-name: "@appium/support" dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2c3d71bc0..32d3111b1 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "dependencies": { "@appium/base-driver": "^9.0.0", "@appium/strongbox": "^0.x", - "@appium/support": "^5.0.3", + "@appium/support": "^6.0.0", "appium-ios-device": "^2.7.25", "appium-ios-simulator": "^6.0.0", "async-lock": "^1.0.0", From deb8ecabc52571e8004bcb2b804b9f7e43fad944 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 6 Dec 2024 12:30:49 +0000 Subject: [PATCH 022/219] chore(release): 8.11.3 [skip ci] ## [8.11.3](https://github.com/appium/WebDriverAgent/compare/v8.11.2...v8.11.3) (2024-12-06) ### Miscellaneous Chores * **deps:** bump @appium/support from 5.1.8 to 6.0.0 ([#960](https://github.com/appium/WebDriverAgent/issues/960)) ([dbeb09c](https://github.com/appium/WebDriverAgent/commit/dbeb09c89f8c02e00a7bdffe7899650d435f3575)) --- CHANGELOG.md | 6 ++++++ WebDriverAgentLib/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ad29b2da..478d31819 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [8.11.3](https://github.com/appium/WebDriverAgent/compare/v8.11.2...v8.11.3) (2024-12-06) + +### Miscellaneous Chores + +* **deps:** bump @appium/support from 5.1.8 to 6.0.0 ([#960](https://github.com/appium/WebDriverAgent/issues/960)) ([dbeb09c](https://github.com/appium/WebDriverAgent/commit/dbeb09c89f8c02e00a7bdffe7899650d435f3575)) + ## [8.11.2](https://github.com/appium/WebDriverAgent/compare/v8.11.1...v8.11.2) (2024-12-03) ### Miscellaneous Chores diff --git a/WebDriverAgentLib/Info.plist b/WebDriverAgentLib/Info.plist index ebf8f6cf9..f100c34c0 100644 --- a/WebDriverAgentLib/Info.plist +++ b/WebDriverAgentLib/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 8.11.2 + 8.11.3 CFBundleSignature ???? CFBundleVersion - 8.11.2 + 8.11.3 NSPrincipalClass diff --git a/package.json b/package.json index 32d3111b1..9df01f49b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "appium-webdriveragent", - "version": "8.11.2", + "version": "8.11.3", "description": "Package bundling WebDriverAgent", "main": "./build/index.js", "types": "./build/index.d.ts", From 916c8c557a9366608df211f33b5b7fbb0354dad3 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Fri, 13 Dec 2024 11:03:11 -0800 Subject: [PATCH 023/219] feat: look for critical notification in respectSystemAlerts (#962) * feat: look for critical notification in respectSystemAlerts * use IN * Update FBSession.m * Use NotificationShortLookView instead as identifier --- WebDriverAgentLib/Routing/FBSession.m | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/WebDriverAgentLib/Routing/FBSession.m b/WebDriverAgentLib/Routing/FBSession.m index a4460b4a8..e8fb95a18 100644 --- a/WebDriverAgentLib/Routing/FBSession.m +++ b/WebDriverAgentLib/Routing/FBSession.m @@ -178,10 +178,13 @@ - (XCUIApplication *)activeApplication if (nil != self.testedApplication) { XCUIApplicationState testedAppState = self.testedApplication.state; if (testedAppState >= XCUIApplicationStateRunningForeground) { - // We look for `SBTransientOverlayWindow` elements for half modals. See https://github.com/appium/WebDriverAgent/pull/946 - NSPredicate *searchPredicate = [NSPredicate predicateWithFormat:@"%K == %@ OR %K == %@", + NSPredicate *searchPredicate = [NSPredicate predicateWithFormat:@"%K == %@ OR %K IN {%@, %@}", @"elementType", @(XCUIElementTypeAlert), - @"identifier", @"SBTransientOverlayWindow"]; + // To look for `SBTransientOverlayWindow` elements. See https://github.com/appium/WebDriverAgent/pull/946 + @"identifier", @"SBTransientOverlayWindow", + // To look for 'criticalAlertSetting' elements https://developer.apple.com/documentation/usernotifications/unnotificationsettings/criticalalertsetting + // See https://github.com/appium/appium/issues/20835 + @"NotificationShortLookView"]; if ([FBConfiguration shouldRespectSystemAlerts] && [[XCUIApplication.fb_systemApplication descendantsMatchingType:XCUIElementTypeAny] matchingPredicate:searchPredicate].count > 0) { From 9734b83f7a228d09566e73c25058432e8e083e50 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 13 Dec 2024 19:08:26 +0000 Subject: [PATCH 024/219] chore(release): 8.12.0 [skip ci] ## [8.12.0](https://github.com/appium/WebDriverAgent/compare/v8.11.3...v8.12.0) (2024-12-13) ### Features * look for critical notification in respectSystemAlerts ([#962](https://github.com/appium/WebDriverAgent/issues/962)) ([916c8c5](https://github.com/appium/WebDriverAgent/commit/916c8c557a9366608df211f33b5b7fbb0354dad3)) --- CHANGELOG.md | 6 ++++++ WebDriverAgentLib/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 478d31819..963a3763a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [8.12.0](https://github.com/appium/WebDriverAgent/compare/v8.11.3...v8.12.0) (2024-12-13) + +### Features + +* look for critical notification in respectSystemAlerts ([#962](https://github.com/appium/WebDriverAgent/issues/962)) ([916c8c5](https://github.com/appium/WebDriverAgent/commit/916c8c557a9366608df211f33b5b7fbb0354dad3)) + ## [8.11.3](https://github.com/appium/WebDriverAgent/compare/v8.11.2...v8.11.3) (2024-12-06) ### Miscellaneous Chores diff --git a/WebDriverAgentLib/Info.plist b/WebDriverAgentLib/Info.plist index f100c34c0..0998ccfbb 100644 --- a/WebDriverAgentLib/Info.plist +++ b/WebDriverAgentLib/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 8.11.3 + 8.12.0 CFBundleSignature ???? CFBundleVersion - 8.11.3 + 8.12.0 NSPrincipalClass diff --git a/package.json b/package.json index 9df01f49b..55dfe122e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "appium-webdriveragent", - "version": "8.11.3", + "version": "8.12.0", "description": "Package bundling WebDriverAgent", "main": "./build/index.js", "types": "./build/index.d.ts", From 17f49ec5a54e97b0ef0d20a3e39fc96b32575e43 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Fri, 3 Jan 2025 17:34:51 +0100 Subject: [PATCH 025/219] chore: Bump eslint (#965) --- .eslintignore | 3 --- .eslintrc.json | 29 --------------------- Scripts/build-webdriveragent.js | 2 +- Scripts/fetch-prebuilt-wda.js | 2 +- eslint.config.mjs | 13 +++++++++ lib/check-dependencies.js | 5 ++-- lib/utils.js | 6 ++--- lib/webdriveragent.js | 4 +-- package.json | 2 +- test/functional/helpers/simulator.js | 4 +-- test/functional/webdriveragent-e2e-specs.js | 6 ++--- 11 files changed, 28 insertions(+), 48 deletions(-) delete mode 100644 .eslintignore delete mode 100644 .eslintrc.json create mode 100644 eslint.config.mjs diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 84930aead..000000000 --- a/.eslintignore +++ /dev/null @@ -1,3 +0,0 @@ -Resources -coverage -build diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 3d7db0846..000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "extends": ["@appium/eslint-config-appium-ts"], - "overrides": [ - { - "files": "test/**/*.js", - "rules": { - "func-names": "off", - "@typescript-eslint/no-var-requires": "off" - } - }, - { - "files": "Scripts/**/*.js", - "parserOptions": {"sourceType": "script"}, - "rules": { - "@typescript-eslint/no-var-requires": "off" - } - }, - { - "files": "ci-jobs/scripts/*.js", - "parserOptions": {"sourceType": "script"}, - "rules": { - "@typescript-eslint/no-var-requires": "off" - } - } - ], - "rules": { - "require-await": "error" - } -} diff --git a/Scripts/build-webdriveragent.js b/Scripts/build-webdriveragent.js index 1958b876d..b37bcbbc9 100644 --- a/Scripts/build-webdriveragent.js +++ b/Scripts/build-webdriveragent.js @@ -34,7 +34,7 @@ async function buildWebDriverAgent (xcodeVersion) { await exec('xcodebuild', ['clean', '-derivedDataPath', DERIVED_DATA_PATH, '-scheme', 'WebDriverAgentRunner'], { cwd: ROOT_DIR }); - } catch (ign) {} + } catch {} // Get Xcode version xcodeVersion = xcodeVersion || await xcode.getVersion(); diff --git a/Scripts/fetch-prebuilt-wda.js b/Scripts/fetch-prebuilt-wda.js index 8bedd9a3d..4bd6840fa 100644 --- a/Scripts/fetch-prebuilt-wda.js +++ b/Scripts/fetch-prebuilt-wda.js @@ -47,7 +47,7 @@ async function fetchPrebuiltWebDriverAgentAssets () { try { const nameOfAgent = _.last(url.split('/')); agentsDownloading.push(downloadAgent(url, path.join(webdriveragentsDir, nameOfAgent))); - } catch (ign) { } + } catch { } } // Wait for them all to finish diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 000000000..020f8c2d2 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,13 @@ +import appiumConfig from '@appium/eslint-config-appium-ts'; + +export default [ + ...appiumConfig, + { + ignores: [ + 'Configurations/**', + 'Fastlane/**', + 'PrivateHeaders/**', + 'WebDriverAgent*/**' + ], + }, +]; diff --git a/lib/check-dependencies.js b/lib/check-dependencies.js index 21c68de60..49903671d 100644 --- a/lib/check-dependencies.js +++ b/lib/check-dependencies.js @@ -2,8 +2,8 @@ import { fs } from '@appium/support'; import _ from 'lodash'; import { exec } from 'teen_process'; import path from 'path'; -import XcodeBuild from './xcodebuild'; -import xcode from 'appium-xcode'; +import {XcodeBuild} from './xcodebuild'; +import * as xcode from 'appium-xcode'; import { WDA_SCHEME, SDK_SIMULATOR, WDA_RUNNER_APP } from './constants'; @@ -22,7 +22,6 @@ async function buildWDASim () { await exec('xcodebuild', args); } -// eslint-disable-next-line require-await export async function checkForDependencies () { log.debug('Dependencies are up to date'); return false; diff --git a/lib/utils.js b/lib/utils.js index f8e7007c1..77ca8f53a 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -27,7 +27,7 @@ const getModuleRoot = _.memoize(function getModuleRoot () { JSON.parse(_fs.readFileSync(manifestPath, 'utf8')).name === 'appium-webdriveragent') { return currentDir; } - } catch (ign) {} + } catch {} currentDir = path.dirname(currentDir); isAtFsRoot = currentDir.length <= path.dirname(currentDir).length; } @@ -86,7 +86,7 @@ async function killAppUsingPattern (pgrepPattern) { intervalMs: 100, }); return; - } catch (ign) { + } catch { // try the next signal } } @@ -121,7 +121,7 @@ async function updateProjectFile (agentPath, newBundleId) { try { // Assuming projectFilePath is in the correct state, create .old from projectFilePath await fs.copyFile(projectFilePath, `${projectFilePath}.old`); - await replaceInFile(projectFilePath, new RegExp(_.escapeRegExp(WDA_RUNNER_BUNDLE_ID), 'g'), newBundleId); // eslint-disable-line no-useless-escape + await replaceInFile(projectFilePath, new RegExp(_.escapeRegExp(WDA_RUNNER_BUNDLE_ID), 'g'), newBundleId); log.debug(`Successfully updated '${projectFilePath}' with bundle id '${newBundleId}'`); } catch (err) { log.debug(`Error updating project file: ${err.message}`); diff --git a/lib/webdriveragent.js b/lib/webdriveragent.js index f5cda7ee3..e47b9c752 100644 --- a/lib/webdriveragent.js +++ b/lib/webdriveragent.js @@ -10,7 +10,7 @@ import { NoSessionProxy } from './no-session-proxy'; import { getWDAUpgradeTimestamp, resetTestProcesses, getPIDsListeningOnPort, BOOTSTRAP_PATH } from './utils'; -import XcodeBuild from './xcodebuild'; +import {XcodeBuild} from './xcodebuild'; import AsyncLock from 'async-lock'; import { exec } from 'teen_process'; import { bundleWDASim } from './check-dependencies'; @@ -417,7 +417,7 @@ export class WebDriverAgent { let status; try { status = await this.getStatus(this.wdaLaunchTimeout); - } catch (err) { + } catch { throw new Error( `Failed to start the preinstalled WebDriverAgent in ${this.wdaLaunchTimeout} ms. ` + `The WebDriverAgent might not be properly built or the device might be locked. ` + diff --git a/package.json b/package.json index 55dfe122e..b1c5ad616 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ }, "homepage": "https://github.com/appium/WebDriverAgent#readme", "devDependencies": { - "@appium/eslint-config-appium-ts": "^0.x", + "@appium/eslint-config-appium-ts": "^1.0.0", "@appium/test-support": "^3.0.0", "@appium/tsconfig": "^0.x", "@appium/types": "^0.x", diff --git a/test/functional/helpers/simulator.js b/test/functional/helpers/simulator.js index 4dd7359df..f315f2035 100644 --- a/test/functional/helpers/simulator.js +++ b/test/functional/helpers/simulator.js @@ -1,5 +1,5 @@ import _ from 'lodash'; -import Simctl from 'node-simctl'; +import { Simctl } from 'node-simctl'; import { retryInterval } from 'asyncbox'; import { killAllSimulators as simKill } from 'appium-ios-simulator'; import { resetTestProcesses } from '../../../lib/utils'; @@ -34,7 +34,7 @@ async function deleteDeviceWithRetry (udid) { const simctl = new Simctl({udid}); try { await retryInterval(10, 1000, simctl.deleteDevice.bind(simctl)); - } catch (ign) {} + } catch {} } diff --git a/test/functional/webdriveragent-e2e-specs.js b/test/functional/webdriveragent-e2e-specs.js index 3cf2862f1..bb1ce67c9 100644 --- a/test/functional/webdriveragent-e2e-specs.js +++ b/test/functional/webdriveragent-e2e-specs.js @@ -1,4 +1,4 @@ -import Simctl from 'node-simctl'; +import { Simctl } from 'node-simctl'; import { getVersion } from 'appium-xcode'; import { getSimulator } from 'appium-ios-simulator'; import { killAllSimulators, shutdownSimulator } from './helpers/simulator'; @@ -89,7 +89,7 @@ describe('WebDriverAgent', function () { await retryInterval(5, 1000, async function () { await shutdownSimulator(device); }); - } catch (ign) {} + } catch {} }); it('should launch agent on a sim', async function () { @@ -106,7 +106,7 @@ describe('WebDriverAgent', function () { const agent = new WebDriverAgent(xcodeVersion, getStartOpts(device)); - agent.xcodebuild.createSubProcess = async function () { // eslint-disable-line require-await + agent.xcodebuild.createSubProcess = async function () { let args = [ '-workspace', `${this.agentPath}dfgs`, From a1b5af60d5257850dac989dff3fdce2ec459efcd Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 3 Jan 2025 16:37:36 +0000 Subject: [PATCH 026/219] chore(release): 8.12.1 [skip ci] ## [8.12.1](https://github.com/appium/WebDriverAgent/compare/v8.12.0...v8.12.1) (2025-01-03) ### Miscellaneous Chores * Bump eslint ([#965](https://github.com/appium/WebDriverAgent/issues/965)) ([17f49ec](https://github.com/appium/WebDriverAgent/commit/17f49ec5a54e97b0ef0d20a3e39fc96b32575e43)) --- CHANGELOG.md | 6 ++++++ WebDriverAgentLib/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 963a3763a..d35fd58bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [8.12.1](https://github.com/appium/WebDriverAgent/compare/v8.12.0...v8.12.1) (2025-01-03) + +### Miscellaneous Chores + +* Bump eslint ([#965](https://github.com/appium/WebDriverAgent/issues/965)) ([17f49ec](https://github.com/appium/WebDriverAgent/commit/17f49ec5a54e97b0ef0d20a3e39fc96b32575e43)) + ## [8.12.0](https://github.com/appium/WebDriverAgent/compare/v8.11.3...v8.12.0) (2024-12-13) ### Features diff --git a/WebDriverAgentLib/Info.plist b/WebDriverAgentLib/Info.plist index 0998ccfbb..3f9b91d92 100644 --- a/WebDriverAgentLib/Info.plist +++ b/WebDriverAgentLib/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 8.12.0 + 8.12.1 CFBundleSignature ???? CFBundleVersion - 8.12.0 + 8.12.1 NSPrincipalClass diff --git a/package.json b/package.json index b1c5ad616..6bddce650 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "appium-webdriveragent", - "version": "8.12.0", + "version": "8.12.1", "description": "Package bundling WebDriverAgent", "main": "./build/index.js", "types": "./build/index.d.ts", From f62afc372c123bdd8dd7bb493f653bb128144d24 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Mon, 13 Jan 2025 08:34:09 +0100 Subject: [PATCH 027/219] chore: Exclude element visibility and accessibility info from the accessibility audit details (#968) --- .../Categories/XCUIApplication+FBHelpers.m | 64 +++++++++++++++---- 1 file changed, 50 insertions(+), 14 deletions(-) diff --git a/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m b/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m index 6cdae945b..2672e3272 100644 --- a/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m +++ b/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m @@ -40,6 +40,13 @@ static NSString* const FBUnknownBundleId = @"unknown"; +static NSString* const FBExclusionAttributeFrame = @"frame"; +static NSString* const FBExclusionAttributeEnabled = @"enabled"; +static NSString* const FBExclusionAttributeVisible = @"visible"; +static NSString* const FBExclusionAttributeAccessible = @"accessible"; +static NSString* const FBExclusionAttributeFocused = @"focused"; + + _Nullable id extractIssueProperty(id issue, NSString *propertyName) { SEL selector = NSSelectorFromString(propertyName); NSMethodSignature *methodSignature = [issue methodSignatureForSelector:selector]; @@ -88,6 +95,17 @@ _Nullable id extractIssueProperty(id issue, NSString *propertyName) { return result; } +NSDictionary *customExclusionAttributesMap(void) { + static dispatch_once_t onceToken; + static NSDictionary *result; + dispatch_once(&onceToken, ^{ + result = @{ + FBExclusionAttributeVisible: FB_XCAXAIsVisibleAttributeName, + FBExclusionAttributeAccessible: FB_XCAXAIsElementAttributeName, + }; + }); + return result; +} @implementation XCUIApplication (FBHelpers) @@ -156,12 +174,26 @@ - (NSDictionary *)fb_tree return [self fb_tree:nil]; } -- (NSDictionary *)fb_tree:(nullable NSSet *) excludedAttributes +- (NSDictionary *)fb_tree:(nullable NSSet *)excludedAttributes { - id snapshot = self.fb_isResolvedFromCache.boolValue - ? self.lastSnapshot - : [self fb_snapshotWithAllAttributesAndMaxDepth:nil]; - return [self.class dictionaryForElement:snapshot recursive:YES excludedAttributes:excludedAttributes]; + // This set includes XCTest-specific internal attribute names, + // while the `excludedAttributes` arg contains human-readable ones + NSMutableSet* includedAttributeNames = [NSMutableSet setWithArray:FBCustomAttributeNames()]; + [includedAttributeNames addObjectsFromArray:FBStandardAttributeNames()]; + if (nil != excludedAttributes) { + for (NSString *attr in excludedAttributes) { + NSString *mappedName = [customExclusionAttributesMap() objectForKey:attr]; + if (nil != mappedName) { + [includedAttributeNames removeObject:attr]; + } + } + } + id snapshot = nil == excludedAttributes + ? [self fb_snapshotWithAllAttributesAndMaxDepth:nil] + : [self fb_snapshotWithAttributes:[includedAttributeNames allObjects] maxDepth:nil]; + return [self.class dictionaryForElement:snapshot + recursive:YES + excludedAttributes:excludedAttributes]; } - (NSDictionary *)fb_accessibilityTree @@ -174,7 +206,7 @@ - (NSDictionary *)fb_accessibilityTree + (NSDictionary *)dictionaryForElement:(id)snapshot recursive:(BOOL)recursive - excludedAttributes:(nullable NSSet *) excludedAttributes + excludedAttributes:(nullable NSSet *)excludedAttributes { NSMutableDictionary *info = [[NSMutableDictionary alloc] init]; info[@"type"] = [FBElementTypeTransformer shortStringWithElementType:snapshot.elementType]; @@ -186,19 +218,19 @@ + (NSDictionary *)dictionaryForElement:(id)snapshot info[@"rect"] = wrappedSnapshot.wdRect; NSDictionary *attributeBlocks = @{ - @"frame": ^{ + FBExclusionAttributeFrame: ^{ return NSStringFromCGRect(wrappedSnapshot.wdFrame); }, - @"enabled": ^{ + FBExclusionAttributeEnabled: ^{ return [@([wrappedSnapshot isWDEnabled]) stringValue]; }, - @"visible": ^{ + FBExclusionAttributeVisible: ^{ return [@([wrappedSnapshot isWDVisible]) stringValue]; }, - @"accessible": ^{ + FBExclusionAttributeAccessible: ^{ return [@([wrappedSnapshot isWDAccessible]) stringValue]; }, - @"focused": ^{ + FBExclusionAttributeFocused: ^{ return [@([wrappedSnapshot isWDFocused]) stringValue]; } }; @@ -206,7 +238,7 @@ + (NSDictionary *)dictionaryForElement:(id)snapshot for (NSString *key in attributeBlocks) { if (excludedAttributes == nil || ![excludedAttributes containsObject:key]) { NSString *value = ((NSString * (^)(void))attributeBlocks[key])(); - if ([key isEqualToString:@"frame"]) { + if ([key isEqualToString:FBExclusionAttributeFrame]) { info[key] = value; } else { info[[NSString stringWithFormat:@"is%@", [key capitalizedString]]] = value; @@ -396,6 +428,8 @@ - (BOOL)fb_dismissKeyboardWithKeyNames:(nullable NSArray *)keyNames return nil; } + // These custom attributes could take too long to fetch, thus excluded + NSSet *customAttributesToExclude = [NSSet setWithArray:[customExclusionAttributesMap() allKeys]]; NSMutableArray *resultArray = [NSMutableArray array]; NSMethodSignature *methodSignature = [self methodSignatureForSelector:selector]; NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature]; @@ -411,9 +445,11 @@ - (BOOL)fb_dismissKeyboardWithKeyNames:(nullable NSArray *)keyNames id extractedElement = extractIssueProperty(issue, @"element"); - id elementSnapshot = [extractedElement fb_takeSnapshot]; + id elementSnapshot = [extractedElement fb_cachedSnapshot] ?: [extractedElement fb_takeSnapshot]; NSDictionary *elementAttributes = elementSnapshot - ? [self.class dictionaryForElement:elementSnapshot recursive:NO excludedAttributes:nil] + ? [self.class dictionaryForElement:elementSnapshot + recursive:NO + excludedAttributes:customAttributesToExclude] : @{}; [resultArray addObject:@{ From 194ddf1d75e9bc2fb741088b801fdf4ff87d099b Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 13 Jan 2025 07:39:09 +0000 Subject: [PATCH 028/219] chore(release): 8.12.2 [skip ci] ## [8.12.2](https://github.com/appium/WebDriverAgent/compare/v8.12.1...v8.12.2) (2025-01-13) ### Miscellaneous Chores * Exclude element visibility and accessibility info from the accessibility audit details ([#968](https://github.com/appium/WebDriverAgent/issues/968)) ([f62afc3](https://github.com/appium/WebDriverAgent/commit/f62afc372c123bdd8dd7bb493f653bb128144d24)) --- CHANGELOG.md | 6 ++++++ WebDriverAgentLib/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d35fd58bc..7fe42c710 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [8.12.2](https://github.com/appium/WebDriverAgent/compare/v8.12.1...v8.12.2) (2025-01-13) + +### Miscellaneous Chores + +* Exclude element visibility and accessibility info from the accessibility audit details ([#968](https://github.com/appium/WebDriverAgent/issues/968)) ([f62afc3](https://github.com/appium/WebDriverAgent/commit/f62afc372c123bdd8dd7bb493f653bb128144d24)) + ## [8.12.1](https://github.com/appium/WebDriverAgent/compare/v8.12.0...v8.12.1) (2025-01-03) ### Miscellaneous Chores diff --git a/WebDriverAgentLib/Info.plist b/WebDriverAgentLib/Info.plist index 3f9b91d92..f263b2ad8 100644 --- a/WebDriverAgentLib/Info.plist +++ b/WebDriverAgentLib/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 8.12.1 + 8.12.2 CFBundleSignature ???? CFBundleVersion - 8.12.1 + 8.12.2 NSPrincipalClass diff --git a/package.json b/package.json index 6bddce650..4134f04db 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "appium-webdriveragent", - "version": "8.12.1", + "version": "8.12.2", "description": "Package bundling WebDriverAgent", "main": "./build/index.js", "types": "./build/index.d.ts", From eca2ed1e4fd0b5a1d31ac305603b6b06faeb8a7d Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Tue, 14 Jan 2025 14:43:55 -0800 Subject: [PATCH 029/219] ci: lock Ruby version to 3.3 (#971) --- azure-templates/bootstrap_steps.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-templates/bootstrap_steps.yml b/azure-templates/bootstrap_steps.yml index 6c96e9ead..14c127e11 100644 --- a/azure-templates/bootstrap_steps.yml +++ b/azure-templates/bootstrap_steps.yml @@ -3,5 +3,5 @@ steps: - script: mkdir -p ./Resources/WebDriverAgent.bundle - task: UseRubyVersion@0 inputs: - versionSpec: '3' + versionSpec: '3.3' addToPath: true From 08f13060119c710f53b34a98c95683287c0365a0 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Thu, 16 Jan 2025 17:44:20 +0100 Subject: [PATCH 030/219] feat: Refactor snapshotting mechanism (#970) BREAKING CHANGE: snapshotTimeout and customSnapshotTimeout settings have been removed as a result of the custom snapshotting logic removal --- .../XCTestManager_ManagerInterface-Protocol.h | 1 + WebDriverAgent.xcodeproj/project.pbxproj | 12 ++ .../FBXCElementSnapshotWrapper+Helpers.h | 13 +- .../FBXCElementSnapshotWrapper+Helpers.m | 38 ++-- .../Categories/XCUIApplication+FBAlert.m | 4 +- .../Categories/XCUIApplication+FBHelpers.m | 24 +-- .../Categories/XCUIElement+FBAccessibility.m | 19 +- .../Categories/XCUIElement+FBCaching.h | 3 - .../Categories/XCUIElement+FBCaching.m | 23 +- .../Categories/XCUIElement+FBFind.m | 2 +- .../Categories/XCUIElement+FBIsVisible.m | 201 +++--------------- .../Categories/XCUIElement+FBPickerWheel.m | 4 +- .../Categories/XCUIElement+FBScrolling.m | 63 +++--- .../Categories/XCUIElement+FBTyping.m | 12 +- .../Categories/XCUIElement+FBUID.m | 4 +- .../Categories/XCUIElement+FBUtilities.h | 39 +--- .../Categories/XCUIElement+FBUtilities.m | 78 +------ .../Categories/XCUIElement+FBVisibleFrame.h | 36 ++++ .../Categories/XCUIElement+FBVisibleFrame.m | 53 +++++ .../XCUIElement+FBWebDriverAttributes.m | 27 +-- WebDriverAgentLib/Commands/FBCustomCommands.m | 3 +- .../Commands/FBElementCommands.m | 72 +++---- .../Commands/FBFindElementCommands.m | 19 +- .../Commands/FBSessionCommands.m | 8 - WebDriverAgentLib/FBAlert.m | 11 +- WebDriverAgentLib/Routing/FBElementCache.h | 14 +- WebDriverAgentLib/Routing/FBElementCache.m | 37 +--- WebDriverAgentLib/Routing/FBResponsePayload.m | 8 +- WebDriverAgentLib/Utilities/FBConfiguration.h | 8 - WebDriverAgentLib/Utilities/FBConfiguration.m | 12 -- WebDriverAgentLib/Utilities/FBSettings.h | 3 - WebDriverAgentLib/Utilities/FBSettings.m | 2 - .../Utilities/FBTVNavigationTracker.m | 4 +- .../Utilities/FBW3CActionsSynthesizer.m | 2 +- .../Utilities/FBXCAXClientProxy.h | 7 +- .../Utilities/FBXCAXClientProxy.m | 18 +- .../Utilities/FBXCodeCompatibility.h | 4 +- .../Utilities/FBXCodeCompatibility.m | 4 +- WebDriverAgentLib/Utilities/FBXPath.m | 5 +- .../Utilities/XCTestPrivateSymbols.h | 3 + .../Utilities/XCTestPrivateSymbols.m | 1 + .../FBElementAttributeTests.m | 3 +- .../IntegrationTests/FBElementSwipingTests.m | 2 +- .../FBW3CTouchActionsIntegrationTests.m | 2 +- .../FBXPathIntegrationTests.m | 4 +- .../XCElementSnapshotHelperTests.m | 31 ++- .../XCElementSnapshotHitPointTests.m | 2 +- .../XCUIElementHelperIntegrationTests.m | 8 +- .../Doubles/XCElementSnapshotDouble.m | 10 + .../UnitTests/Doubles/XCUIElementDouble.h | 3 +- .../UnitTests/Doubles/XCUIElementDouble.m | 2 +- .../UnitTests/FBElementCacheTests.m | 2 - .../Doubles/XCUIElementDouble.h | 1 - 53 files changed, 350 insertions(+), 621 deletions(-) create mode 100644 WebDriverAgentLib/Categories/XCUIElement+FBVisibleFrame.h create mode 100644 WebDriverAgentLib/Categories/XCUIElement+FBVisibleFrame.m diff --git a/PrivateHeaders/XCTest/XCTestManager_ManagerInterface-Protocol.h b/PrivateHeaders/XCTest/XCTestManager_ManagerInterface-Protocol.h index 8ed03ebf7..d68f25c17 100644 --- a/PrivateHeaders/XCTest/XCTestManager_ManagerInterface-Protocol.h +++ b/PrivateHeaders/XCTest/XCTestManager_ManagerInterface-Protocol.h @@ -27,6 +27,7 @@ - (void)_XCT_requestElementAtPoint:(CGPoint)arg1 reply:(void (^)(id/*XCAccessibilityElement*/, NSError *))arg2; - (void)_XCT_fetchParameterizedAttributeForElement:(id/*XCAccessibilityElement*/)arg1 attributes:(NSNumber *)arg2 parameter:(id)arg3 reply:(void (^)(id, NSError *))arg4; - (void)_XCT_setAttribute:(NSNumber *)arg1 value:(id)arg2 element:(id/*XCAccessibilityElement*/)arg3 reply:(void (^)(BOOL, NSError *))arg4; +- (void)_XCT_fetchAttributes:(id)attributes forElement:(id)element reply:(void (^)(NSDictionary *, NSError *))reply; - (void)_XCT_fetchAttributesForElement:(id/*XCAccessibilityElement*/)arg1 attributes:(NSArray *)arg2 reply:(void (^)(NSDictionary *, NSError *))arg3; - (void)_XCT_terminateApplicationWithBundleID:(NSString *)arg1 completion:(void (^)(NSError *))arg2; - (void)_XCT_performAccessibilityAction:(int)arg1 onElement:(id/*XCAccessibilityElement*/)arg2 withValue:(id)arg3 reply:(void (^)(NSError *))arg4; diff --git a/WebDriverAgent.xcodeproj/project.pbxproj b/WebDriverAgent.xcodeproj/project.pbxproj index db4465848..2fd346017 100644 --- a/WebDriverAgent.xcodeproj/project.pbxproj +++ b/WebDriverAgent.xcodeproj/project.pbxproj @@ -451,6 +451,10 @@ 71A7EAFA1E224648001DA4F2 /* FBClassChainQueryParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 71A7EAF81E224648001DA4F2 /* FBClassChainQueryParser.m */; }; 71A7EAFC1E229302001DA4F2 /* FBClassChainTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 71A7EAFB1E229302001DA4F2 /* FBClassChainTests.m */; }; 71ACF5B8242F2FDC00F0AAD4 /* FBSafariAlertTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 71ACF5B7242F2FDC00F0AAD4 /* FBSafariAlertTests.m */; }; + 71AE3CF72D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 71AE3CF52D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.h */; }; + 71AE3CF82D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 71AE3CF62D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.m */; }; + 71AE3CF92D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 71AE3CF52D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.h */; }; + 71AE3CFA2D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 71AE3CF62D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.m */; }; 71B155DA23070ECF00646AFB /* FBHTTPStatusCodes.h in Headers */ = {isa = PBXBuildFile; fileRef = 71B155D923070ECF00646AFB /* FBHTTPStatusCodes.h */; settings = {ATTRIBUTES = (Public, ); }; }; 71B155DC230711E900646AFB /* FBCommandStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = 71B155DB230711E900646AFB /* FBCommandStatus.m */; }; 71B155DF23080CA600646AFB /* FBProtocolHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 71B155DD23080CA600646AFB /* FBProtocolHelpers.h */; }; @@ -1050,6 +1054,8 @@ 71A7EAF81E224648001DA4F2 /* FBClassChainQueryParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBClassChainQueryParser.m; sourceTree = ""; }; 71A7EAFB1E229302001DA4F2 /* FBClassChainTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBClassChainTests.m; sourceTree = ""; }; 71ACF5B7242F2FDC00F0AAD4 /* FBSafariAlertTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBSafariAlertTests.m; sourceTree = ""; }; + 71AE3CF52D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "XCUIElement+FBVisibleFrame.h"; sourceTree = ""; }; + 71AE3CF62D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "XCUIElement+FBVisibleFrame.m"; sourceTree = ""; }; 71B155D923070ECF00646AFB /* FBHTTPStatusCodes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FBHTTPStatusCodes.h; sourceTree = ""; }; 71B155DB230711E900646AFB /* FBCommandStatus.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBCommandStatus.m; sourceTree = ""; }; 71B155DD23080CA600646AFB /* FBProtocolHelpers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FBProtocolHelpers.h; sourceTree = ""; }; @@ -1781,6 +1787,8 @@ 71B49EC61ED1A58100D51AD6 /* XCUIElement+FBUID.m */, EEE3763F1D59F81400ED88DD /* XCUIElement+FBUtilities.h */, EEE376401D59F81400ED88DD /* XCUIElement+FBUtilities.m */, + 71AE3CF52D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.h */, + 71AE3CF62D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.m */, EEE376471D59FAE900ED88DD /* XCUIElement+FBWebDriverAttributes.h */, EEE376481D59FAE900ED88DD /* XCUIElement+FBWebDriverAttributes.m */, 641EE7042240CDCF00173FCB /* XCUIElement+FBTVFocuse.h */, @@ -2399,6 +2407,7 @@ 641EE6A42240C5CA00173FCB /* FBCommandHandler.h in Headers */, 641EE6A52240C5CA00173FCB /* FBSessionCommands.h in Headers */, 641EE70C2240CE2D00173FCB /* FBTVNavigationTracker.h in Headers */, + 71AE3CF72D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.h in Headers */, 641EE6A62240C5CA00173FCB /* FBImageProcessor.h in Headers */, 641EE6A72240C5CA00173FCB /* FBSession-Private.h in Headers */, 641EE6A82240C5CA00173FCB /* NSString+FBXMLSafeString.h in Headers */, @@ -2585,6 +2594,7 @@ 714EAA0D2673FDFE005C5B47 /* FBCapabilities.h in Headers */, EE35AD5C1E3B77D600A02D78 /* XCTNSPredicateExpectation.h in Headers */, EE35AD521E3B77D600A02D78 /* XCTestObservationCenter.h in Headers */, + 71AE3CF92D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.h in Headers */, EE35AD5B1E3B77D600A02D78 /* XCTNSNotificationExpectation.h in Headers */, E444DC97249131D40060D7EB /* HTTPServer.h in Headers */, E444DCAE24913C220060D7EB /* HTTPResponseProxy.h in Headers */, @@ -3160,6 +3170,7 @@ 641EE60E2240C5CA00173FCB /* XCUIElement+FBTyping.m in Sources */, 641EE60F2240C5CA00173FCB /* XCUIElement+FBAccessibility.m in Sources */, 641EE6102240C5CA00173FCB /* FBImageUtils.m in Sources */, + 71AE3CF82D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.m in Sources */, 641EE6112240C5CA00173FCB /* FBSession.m in Sources */, 641EE6122240C5CA00173FCB /* FBFindElementCommands.m in Sources */, 71A5C67629A4F39600421C37 /* XCTIssue+FBPatcher.m in Sources */, @@ -3232,6 +3243,7 @@ 713AE576243A53BE0000D657 /* FBW3CActionsHelpers.m in Sources */, 71B155E123080CA600646AFB /* FBProtocolHelpers.m in Sources */, EE158AB11CBD456F00A3E3F0 /* XCUIElement+FBIsVisible.m in Sources */, + 71AE3CFA2D38EE8E0039FC36 /* XCUIElement+FBVisibleFrame.m in Sources */, EEBBD48C1D47746D00656A81 /* XCUIElement+FBFind.m in Sources */, EE158ADD1CBD456F00A3E3F0 /* FBResponsePayload.m in Sources */, E444DCB524913C220060D7EB /* RouteRequest.m in Sources */, diff --git a/WebDriverAgentLib/Categories/FBXCElementSnapshotWrapper+Helpers.h b/WebDriverAgentLib/Categories/FBXCElementSnapshotWrapper+Helpers.h index 4ce84f88b..a4ebdcaea 100644 --- a/WebDriverAgentLib/Categories/FBXCElementSnapshotWrapper+Helpers.h +++ b/WebDriverAgentLib/Categories/FBXCElementSnapshotWrapper+Helpers.h @@ -58,9 +58,11 @@ NS_ASSUME_NONNULL_BEGIN @param attribute attribute's accessibility identifier. Can be one of `XC_kAXXCAttribute`-prefixed attribute names. - @return value for given accessibility property identifier + @param error Error instance in case of a failure + @return value for given accessibility property identifier or nil in case of failure */ -- (nullable id)fb_attributeValue:(NSString *)attribute; +- (nullable id)fb_attributeValue:(NSString *)attribute + error:(NSError **)error; /** Method used to determine whether given element matches receiver by comparing it's parameters except frame. @@ -87,13 +89,6 @@ NS_ASSUME_NONNULL_BEGIN /**! Human-readable snapshot description */ - (NSString *)fb_description; -/** - Returns the snapshot visibleFrame with a fallback to direct attribute retrieval from FBXCAXClient in case of a snapshot fault (nil visibleFrame) - - @return the snapshot visibleFrame - */ -- (CGRect)fb_visibleFrameWithFallback; - /** Wrapper for Apple's hitpoint, thats resolves few known issues diff --git a/WebDriverAgentLib/Categories/FBXCElementSnapshotWrapper+Helpers.m b/WebDriverAgentLib/Categories/FBXCElementSnapshotWrapper+Helpers.m index c16a1a848..c3a70f1f9 100644 --- a/WebDriverAgentLib/Categories/FBXCElementSnapshotWrapper+Helpers.m +++ b/WebDriverAgentLib/Categories/FBXCElementSnapshotWrapper+Helpers.m @@ -10,9 +10,11 @@ #import "FBXCElementSnapshotWrapper+Helpers.h" #import "FBFindElementCommands.h" +#import "FBErrorBuilder.h" #import "FBRunLoopSpinner.h" #import "FBLogger.h" #import "FBXCElementSnapshot.h" +#import "FBXCTestDaemonsProxy.h" #import "FBXCAXClientProxy.h" #import "XCTestDriver.h" #import "XCTestPrivateSymbols.h" @@ -20,6 +22,8 @@ #import "XCUIElement+FBWebDriverAttributes.h" #import "XCUIHitPointResult.h" +#define ATTRIBUTE_FETCH_WARN_TIME_LIMIT 0.05 + inline static BOOL isSnapshotTypeAmongstGivenTypes(id snapshot, NSArray *types); @@ -65,10 +69,17 @@ - (NSString *)fb_description } - (id)fb_attributeValue:(NSString *)attribute + error:(NSError **)error { + NSDate *start = [NSDate date]; NSDictionary *result = [FBXCAXClientProxy.sharedClient attributesForElement:[self accessibilityElement] - attributes:@[attribute]]; - return result[attribute]; + attributes:@[attribute] + error:error]; + NSTimeInterval elapsed = ABS([start timeIntervalSinceNow]); + if (elapsed > ATTRIBUTE_FETCH_WARN_TIME_LIMIT) { + NSLog(@"! Fetching of %@ value for %@ took %@s", attribute, self.fb_description, @(elapsed)); + } + return [result objectForKey:attribute]; } inline static BOOL areValuesEqual(id value1, id value2); @@ -140,29 +151,6 @@ - (BOOL)fb_framelessFuzzyMatchesElement:(id)snapshot return targetCellSnapshot; } -- (CGRect)fb_visibleFrameWithFallback -{ - CGRect thisVisibleFrame = [self visibleFrame]; - if (!CGRectIsEmpty(thisVisibleFrame)) { - return thisVisibleFrame; - } - - NSDictionary *visibleFrameDict = (NSDictionary*)[self fb_attributeValue:@"XC_kAXXCAttributeVisibleFrame"]; - if (visibleFrameDict == nil) { - return thisVisibleFrame; - } - - id x = [visibleFrameDict objectForKey:@"X"]; - id y = [visibleFrameDict objectForKey:@"Y"]; - id height = [visibleFrameDict objectForKey:@"Height"]; - id width = [visibleFrameDict objectForKey:@"Width"]; - if (x != nil && y != nil && height != nil && width != nil) { - return CGRectMake([x doubleValue], [y doubleValue], [width doubleValue], [height doubleValue]); - } - - return thisVisibleFrame; -} - - (NSValue *)fb_hitPoint { NSError *error; diff --git a/WebDriverAgentLib/Categories/XCUIApplication+FBAlert.m b/WebDriverAgentLib/Categories/XCUIApplication+FBAlert.m index 38b6586ef..878be80b0 100644 --- a/WebDriverAgentLib/Categories/XCUIApplication+FBAlert.m +++ b/WebDriverAgentLib/Categories/XCUIApplication+FBAlert.m @@ -52,7 +52,7 @@ - (nullable XCUIElement *)fb_alertElementFromSafariWithScrollView:(XCUIElement * // and conatins at least one text view __block NSUInteger buttonsCount = 0; __block NSUInteger textViewsCount = 0; - id snapshot = candidate.fb_cachedSnapshot ?: candidate.fb_takeSnapshot; + id snapshot = candidate.fb_cachedSnapshot ?: [candidate fb_takeSnapshot:YES]; [snapshot enumerateDescendantsUsingBlock:^(id descendant) { XCUIElementType curType = descendant.elementType; if (curType == XCUIElementTypeButton) { @@ -73,7 +73,7 @@ - (XCUIElement *)fb_alertElement if (nil == alert) { return nil; } - id alertSnapshot = alert.fb_cachedSnapshot ?: alert.fb_takeSnapshot; + id alertSnapshot = alert.fb_cachedSnapshot ?: [alert fb_takeSnapshot:YES]; if (alertSnapshot.elementType == XCUIElementTypeAlert) { return alert; diff --git a/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m b/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m index 2672e3272..03d4407f2 100644 --- a/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m +++ b/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m @@ -176,21 +176,7 @@ - (NSDictionary *)fb_tree - (NSDictionary *)fb_tree:(nullable NSSet *)excludedAttributes { - // This set includes XCTest-specific internal attribute names, - // while the `excludedAttributes` arg contains human-readable ones - NSMutableSet* includedAttributeNames = [NSMutableSet setWithArray:FBCustomAttributeNames()]; - [includedAttributeNames addObjectsFromArray:FBStandardAttributeNames()]; - if (nil != excludedAttributes) { - for (NSString *attr in excludedAttributes) { - NSString *mappedName = [customExclusionAttributesMap() objectForKey:attr]; - if (nil != mappedName) { - [includedAttributeNames removeObject:attr]; - } - } - } - id snapshot = nil == excludedAttributes - ? [self fb_snapshotWithAllAttributesAndMaxDepth:nil] - : [self fb_snapshotWithAttributes:[includedAttributeNames allObjects] maxDepth:nil]; + id snapshot = [self fb_takeSnapshot:YES]; return [self.class dictionaryForElement:snapshot recursive:YES excludedAttributes:excludedAttributes]; @@ -198,9 +184,7 @@ - (NSDictionary *)fb_tree:(nullable NSSet *)excludedAttributes - (NSDictionary *)fb_accessibilityTree { - id snapshot = self.fb_isResolvedFromCache.boolValue - ? self.lastSnapshot - : [self fb_snapshotWithAllAttributesAndMaxDepth:nil]; + id snapshot = [self fb_takeSnapshot:YES]; return [self.class accessibilityInfoForElement:snapshot]; } @@ -445,8 +429,8 @@ - (BOOL)fb_dismissKeyboardWithKeyNames:(nullable NSArray *)keyNames id extractedElement = extractIssueProperty(issue, @"element"); - id elementSnapshot = [extractedElement fb_cachedSnapshot] ?: [extractedElement fb_takeSnapshot]; - NSDictionary *elementAttributes = elementSnapshot + id elementSnapshot = [extractedElement fb_cachedSnapshot] ?: [extractedElement fb_takeSnapshot:NO]; + NSDictionary *elementAttributes = elementSnapshot ? [self.class dictionaryForElement:elementSnapshot recursive:NO excludedAttributes:customAttributesToExclude] diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBAccessibility.m b/WebDriverAgentLib/Categories/XCUIElement+FBAccessibility.m index 327b2171a..944907c15 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBAccessibility.m +++ b/WebDriverAgentLib/Categories/XCUIElement+FBAccessibility.m @@ -18,8 +18,7 @@ @implementation XCUIElement (FBAccessibility) - (BOOL)fb_isAccessibilityElement { - id snapshot = [self fb_snapshotWithAttributes:@[FB_XCAXAIsElementAttributeName] - maxDepth:@1]; + id snapshot = [self fb_takeSnapshot:NO]; return [FBXCElementSnapshotWrapper ensureWrapped:snapshot].fb_isAccessibilityElement; } @@ -33,8 +32,20 @@ - (BOOL)fb_isAccessibilityElement if (nil != isAccessibilityElement) { return isAccessibilityElement.boolValue; } - - return [(NSNumber *)[self fb_attributeValue:FB_XCAXAIsElementAttributeName] boolValue]; + + NSError *error; + NSNumber *attributeValue = [self fb_attributeValue:FB_XCAXAIsElementAttributeName + error:&error]; + if (nil != attributeValue) { + NSMutableDictionary *updatedValue = [NSMutableDictionary dictionaryWithDictionary:self.additionalAttributes ?: @{}]; + [updatedValue setObject:attributeValue forKey:FB_XCAXAIsElementAttribute]; + self.snapshot.additionalAttributes = updatedValue.copy; + return [attributeValue boolValue]; + } + + NSLog(@"Cannot determine accessibility of '%@' natively: %@. Defaulting to: %@", + self.fb_description, error.description, @(NO)); + return NO; } @end diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBCaching.h b/WebDriverAgentLib/Categories/XCUIElement+FBCaching.h index 109a26371..a36039419 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBCaching.h +++ b/WebDriverAgentLib/Categories/XCUIElement+FBCaching.h @@ -13,9 +13,6 @@ NS_ASSUME_NONNULL_BEGIN @interface XCUIElement (FBCaching) -/*! This property is set to YES if the given element has been resolved from the cache, so it is safe to use the `lastSnapshot` property */ -@property (nullable, nonatomic) NSNumber *fb_isResolvedFromCache; - @property (nonatomic, readonly) NSString *fb_cacheId; @end diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBCaching.m b/WebDriverAgentLib/Categories/XCUIElement+FBCaching.m index faa42ea86..ebf4ea6fa 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBCaching.m +++ b/WebDriverAgentLib/Categories/XCUIElement+FBCaching.m @@ -18,20 +18,6 @@ @implementation XCUIElement (FBCaching) -static char XCUIELEMENT_IS_RESOLVED_FROM_CACHE_KEY; - -@dynamic fb_isResolvedFromCache; - -- (void)setFb_isResolvedFromCache:(NSNumber *)isResolvedFromCache -{ - objc_setAssociatedObject(self, &XCUIELEMENT_IS_RESOLVED_FROM_CACHE_KEY, isResolvedFromCache, OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - -- (NSNumber *)fb_isResolvedFromCache -{ - return (NSNumber *)objc_getAssociatedObject(self, &XCUIELEMENT_IS_RESOLVED_FROM_CACHE_KEY); -} - static char XCUIELEMENT_CACHE_ID_KEY; @dynamic fb_cacheId; @@ -43,14 +29,7 @@ - (NSString *)fb_cacheId return (NSString *)result; } - NSString *uid; - if ([self isKindOfClass:XCUIApplication.class]) { - uid = self.fb_uid; - } else { - id snapshot = self.fb_cachedSnapshot ?: self.fb_takeSnapshot; - uid = [FBXCElementSnapshotWrapper wdUIDWithSnapshot:snapshot]; - } - + NSString *uid = self.fb_uid; objc_setAssociatedObject(self, &XCUIELEMENT_CACHE_ID_KEY, uid, OBJC_ASSOCIATION_RETAIN_NONATOMIC); return uid; } diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBFind.m b/WebDriverAgentLib/Categories/XCUIElement+FBFind.m index 4d46f4c8f..e799be557 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBFind.m +++ b/WebDriverAgentLib/Categories/XCUIElement+FBFind.m @@ -110,7 +110,7 @@ @implementation XCUIElement (FBFind) matchingSnapshots = @[snapshot]; } return [self fb_filterDescendantsWithSnapshots:matchingSnapshots - selfUID:[FBXCElementSnapshotWrapper wdUIDWithSnapshot:self.lastSnapshot] + selfUID:self.fb_uid onlyChildren:NO]; } diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBIsVisible.m b/WebDriverAgentLib/Categories/XCUIElement+FBIsVisible.m index 87841fc38..80ee1bd9b 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBIsVisible.m +++ b/WebDriverAgentLib/Categories/XCUIElement+FBIsVisible.m @@ -9,24 +9,23 @@ #import "XCUIElement+FBIsVisible.h" -#import "FBConfiguration.h" #import "FBElementUtils.h" -#import "FBMathUtils.h" -#import "FBActiveAppDetectionPoint.h" -#import "FBSession.h" -#import "FBXCAccessibilityElement.h" #import "FBXCodeCompatibility.h" #import "FBXCElementSnapshotWrapper+Helpers.h" #import "XCUIElement+FBUtilities.h" -#import "XCUIElement+FBUID.h" +#import "XCUIElement+FBVisibleFrame.h" #import "XCTestPrivateSymbols.h" +NSNumber* _Nullable fetchSnapshotVisibility(id snapshot) +{ + return nil == snapshot.additionalAttributes ? nil : snapshot.additionalAttributes[FB_XCAXAIsVisibleAttribute]; +} + @implementation XCUIElement (FBIsVisible) - (BOOL)fb_isVisible { - id snapshot = [self fb_snapshotWithAttributes:@[FB_XCAXAIsVisibleAttributeName] - maxDepth:@1]; + id snapshot = [self fb_takeSnapshot:NO]; return [FBXCElementSnapshotWrapper ensureWrapped:snapshot].fb_isVisible; } @@ -34,187 +33,43 @@ - (BOOL)fb_isVisible @implementation FBXCElementSnapshotWrapper (FBIsVisible) -+ (NSString *)fb_uniqIdWithSnapshot:(id)snapshot -{ - return [FBXCElementSnapshotWrapper wdUIDWithSnapshot:snapshot] ?: [NSString stringWithFormat:@"%p", (void *)snapshot]; -} - -- (nullable NSNumber *)fb_cachedVisibilityValue +- (BOOL)fb_hasVisibleDescendants { - NSMutableDictionary *cache = FBSession.activeSession.elementsVisibilityCache; - if (nil == cache) { - return nil; - } - - NSDictionary *result = cache[@(self.generation)]; - if (nil == result) { - // There is no need to keep the cached data for the previous generations - [cache removeAllObjects]; - cache[@(self.generation)] = [NSMutableDictionary dictionary]; - return nil; - } - return result[[self.class fb_uniqIdWithSnapshot:self.snapshot]]; -} - -- (BOOL)fb_cacheVisibilityWithValue:(BOOL)isVisible - forAncestors:(nullable NSArray> *)ancestors -{ - NSMutableDictionary *cache = FBSession.activeSession.elementsVisibilityCache; - if (nil == cache) { - return isVisible; - } - NSMutableDictionary *destination = cache[@(self.generation)]; - if (nil == destination) { - return isVisible; - } - - NSNumber *visibleObj = [NSNumber numberWithBool:isVisible]; - destination[[self.class fb_uniqIdWithSnapshot:self.snapshot]] = visibleObj; - if (isVisible && nil != ancestors) { - // if an element is visible then all its ancestors must be visible as well - for (id ancestor in ancestors) { - NSString *ancestorId = [self.class fb_uniqIdWithSnapshot:ancestor]; - if (nil == destination[ancestorId]) { - destination[ancestorId] = visibleObj; - } - } - } - return isVisible; -} - -- (CGRect)fb_frameInContainer:(id)container - hierarchyIntersection:(nullable NSValue *)intersectionRectange -{ - CGRect currentRectangle = nil == intersectionRectange ? self.frame : [intersectionRectange CGRectValue]; - id parent = self.parent; - CGRect parentFrame = parent.frame; - CGRect containerFrame = container.frame; - if (CGSizeEqualToSize(parentFrame.size, CGSizeZero) && - CGPointEqualToPoint(parentFrame.origin, CGPointZero)) { - // Special case (or XCTest bug). Shift the origin and return immediately after shift - id nextParent = parent.parent; - BOOL isGrandparent = YES; - while (nextParent && nextParent != container) { - CGRect nextParentFrame = nextParent.frame; - if (isGrandparent && - CGSizeEqualToSize(nextParentFrame.size, CGSizeZero) && - CGPointEqualToPoint(nextParentFrame.origin, CGPointZero)) { - // Double zero-size container inclusion means that element coordinates are absolute - return CGRectIntersection(currentRectangle, containerFrame); - } - isGrandparent = NO; - if (!CGPointEqualToPoint(nextParentFrame.origin, CGPointZero)) { - currentRectangle.origin.x += nextParentFrame.origin.x; - currentRectangle.origin.y += nextParentFrame.origin.y; - return CGRectIntersection(currentRectangle, containerFrame); - } - nextParent = nextParent.parent; - } - return CGRectIntersection(currentRectangle, containerFrame); - } - // Skip parent containers if they are outside of the viewport - CGRect intersectionWithParent = CGRectIntersectsRect(parentFrame, containerFrame) || parent.elementType != XCUIElementTypeOther - ? CGRectIntersection(currentRectangle, parentFrame) - : currentRectangle; - if (CGRectIsEmpty(intersectionWithParent) && - parent != container && - self.elementType == XCUIElementTypeOther) { - // Special case (or XCTest bug). Shift the origin - if (CGSizeEqualToSize(parentFrame.size, containerFrame.size) || - // The size might be inverted in landscape - CGSizeEqualToSize(parentFrame.size, CGSizeMake(containerFrame.size.height, containerFrame.size.width)) || - CGSizeEqualToSize(self.frame.size, CGSizeZero)) { - // Covers ActivityListView and RemoteBridgeView cases - currentRectangle.origin.x += parentFrame.origin.x; - currentRectangle.origin.y += parentFrame.origin.y; - return CGRectIntersection(currentRectangle, containerFrame); - } - } - if (CGRectIsEmpty(intersectionWithParent) || parent == container) { - return intersectionWithParent; - } - return [[FBXCElementSnapshotWrapper ensureWrapped:parent] fb_frameInContainer:container - hierarchyIntersection:[NSValue valueWithCGRect:intersectionWithParent]]; -} - -- (BOOL)fb_hasAnyVisibleLeafs -{ - NSArray> *children = self.children; - if (0 == children.count) { - return self.fb_isVisible; - } - - for (id child in children) { - if ([FBXCElementSnapshotWrapper ensureWrapped:child].fb_hasAnyVisibleLeafs) { + for (id descendant in (self._allDescendants ?: @[])) { + if ([fetchSnapshotVisibility(descendant) boolValue]) { return YES; } } - return NO; } - (BOOL)fb_isVisible { - NSNumber *isVisible = self.additionalAttributes[FB_XCAXAIsVisibleAttribute]; - if (isVisible != nil) { + NSNumber *isVisible = fetchSnapshotVisibility(self); + if (nil != isVisible) { return isVisible.boolValue; } - - NSNumber *cachedValue = [self fb_cachedVisibilityValue]; - if (nil != cachedValue) { - return [cachedValue boolValue]; - } - CGRect selfFrame = self.frame; - if (CGRectIsEmpty(selfFrame)) { - return [self fb_cacheVisibilityWithValue:NO forAncestors:nil]; + // Fetching the attribute value is expensive. + // Shortcircuit here to save time and assume if any of descendants + // is already determined as visible then the container should be visible as well + if ([self fb_hasVisibleDescendants]) { + return YES; } - NSArray> *ancestors = self.fb_ancestors; - if ([FBConfiguration shouldUseTestManagerForVisibilityDetection]) { - BOOL visibleAttrValue = [(NSNumber *)[self fb_attributeValue:FB_XCAXAIsVisibleAttributeName] boolValue]; - return [self fb_cacheVisibilityWithValue:visibleAttrValue forAncestors:ancestors]; + NSError *error; + NSNumber *attributeValue = [self fb_attributeValue:FB_XCAXAIsVisibleAttributeName + error:&error]; + if (nil != attributeValue) { + NSMutableDictionary *updatedValue = [NSMutableDictionary dictionaryWithDictionary:self.additionalAttributes ?: @{}]; + [updatedValue setObject:attributeValue forKey:FB_XCAXAIsVisibleAttribute]; + self.snapshot.additionalAttributes = updatedValue.copy; + return [attributeValue boolValue]; } - id parentWindow = ancestors.count > 1 ? [ancestors objectAtIndex:ancestors.count - 2] : nil; - CGRect visibleRect = selfFrame; - if (nil != parentWindow) { - visibleRect = [self fb_frameInContainer:parentWindow hierarchyIntersection:nil]; - } - if (CGRectIsEmpty(visibleRect)) { - return [self fb_cacheVisibilityWithValue:NO forAncestors:ancestors]; - } - CGPoint midPoint = CGPointMake(visibleRect.origin.x + visibleRect.size.width / 2, - visibleRect.origin.y + visibleRect.size.height / 2); - id hitElement = [FBActiveAppDetectionPoint axElementWithPoint:midPoint]; - if (nil != hitElement) { - if (FBIsAXElementEqualToOther(self.accessibilityElement, hitElement)) { - return [self fb_cacheVisibilityWithValue:YES forAncestors:ancestors]; - } - for (id ancestor in ancestors) { - if (FBIsAXElementEqualToOther(hitElement, ancestor.accessibilityElement)) { - return [self fb_cacheVisibilityWithValue:YES forAncestors:ancestors]; - } - } - } - if (self.children.count > 0) { - if (nil != hitElement) { - for (id descendant in self._allDescendants) { - if (FBIsAXElementEqualToOther(hitElement, descendant.accessibilityElement)) { - return [self fb_cacheVisibilityWithValue:YES - forAncestors:[FBXCElementSnapshotWrapper ensureWrapped:descendant].fb_ancestors]; - } - } - } - if (self.fb_hasAnyVisibleLeafs) { - return [self fb_cacheVisibilityWithValue:YES forAncestors:ancestors]; - } - } else if (nil == hitElement) { - // Sometimes XCTest returns nil for leaf elements hit test even if such elements are hittable - // Assume such elements are visible if their rectInContainer is visible - return [self fb_cacheVisibilityWithValue:YES forAncestors:ancestors]; - } - return [self fb_cacheVisibilityWithValue:NO forAncestors:ancestors]; + NSLog(@"Cannot determine visiblity of %@ natively: %@. Defaulting to: %@", + self.fb_description, error.description, @(NO)); + return NO; } @end diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBPickerWheel.m b/WebDriverAgentLib/Categories/XCUIElement+FBPickerWheel.m index 71ebaf652..881081fa1 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBPickerWheel.m +++ b/WebDriverAgentLib/Categories/XCUIElement+FBPickerWheel.m @@ -23,9 +23,7 @@ @implementation XCUIElement (FBPickerWheel) - (BOOL)fb_scrollWithOffset:(CGFloat)relativeHeightOffset error:(NSError **)error { - id snapshot = self.fb_isResolvedFromCache.boolValue - ? self.lastSnapshot - : self.fb_takeSnapshot; + id snapshot = [self fb_takeSnapshot:NO]; NSString *previousValue = snapshot.value; XCUICoordinate *startCoord = [self coordinateWithNormalizedOffset:CGVectorMake(0.5, 0.5)]; XCUICoordinate *endCoord = [startCoord coordinateWithOffset:CGVectorMake(0.0, relativeHeightOffset * snapshot.frame.size.height)]; diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBScrolling.m b/WebDriverAgentLib/Categories/XCUIElement+FBScrolling.m index 52be1a557..4ebd14b32 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBScrolling.m +++ b/WebDriverAgentLib/Categories/XCUIElement+FBScrolling.m @@ -20,9 +20,11 @@ #import "XCUIApplication.h" #import "XCUICoordinate.h" #import "XCUIElement+FBIsVisible.h" +#import "XCUIElement+FBVisibleFrame.h" #import "XCUIElement.h" #import "XCUIElement+FBUtilities.h" #import "XCUIElement+FBWebDriverAttributes.h" +#import "XCTestPrivateSymbols.h" const CGFloat FBFuzzyPointThreshold = 20.f; //Smallest determined value that is not interpreted as touch const CGFloat FBScrollToVisibleNormalizedDistance = .5f; @@ -47,45 +49,35 @@ @implementation XCUIElement (FBScrolling) - (BOOL)fb_nativeScrollToVisibleWithError:(NSError **)error { - id snapshot = self.fb_isResolvedFromCache.boolValue - ? self.lastSnapshot - : self.fb_takeSnapshot; + id snapshot = [self fb_takeSnapshot:YES]; return nil != [self _hitPointByAttemptingToScrollToVisibleSnapshot:snapshot error:error]; } - (void)fb_scrollUpByNormalizedDistance:(CGFloat)distance { - id snapshot = self.fb_isResolvedFromCache.boolValue - ? self.lastSnapshot - : self.fb_takeSnapshot; + id snapshot = [self fb_takeSnapshot:YES]; [[FBXCElementSnapshotWrapper ensureWrapped:snapshot] fb_scrollUpByNormalizedDistance:distance inApplication:self.application]; } - (void)fb_scrollDownByNormalizedDistance:(CGFloat)distance { - id snapshot = self.fb_isResolvedFromCache.boolValue - ? self.lastSnapshot - : self.fb_takeSnapshot; + id snapshot = [self fb_takeSnapshot:YES]; [[FBXCElementSnapshotWrapper ensureWrapped:snapshot] fb_scrollDownByNormalizedDistance:distance inApplication:self.application]; } - (void)fb_scrollLeftByNormalizedDistance:(CGFloat)distance { - id snapshot = self.fb_isResolvedFromCache.boolValue - ? self.lastSnapshot - : self.fb_takeSnapshot; + id snapshot = [self fb_takeSnapshot:YES]; [[FBXCElementSnapshotWrapper ensureWrapped:snapshot] fb_scrollLeftByNormalizedDistance:distance inApplication:self.application]; } - (void)fb_scrollRightByNormalizedDistance:(CGFloat)distance { - id snapshot = self.fb_isResolvedFromCache.boolValue - ? self.lastSnapshot - : self.fb_takeSnapshot; + id snapshot = [self fb_takeSnapshot:YES]; [[FBXCElementSnapshotWrapper ensureWrapped:snapshot] fb_scrollRightByNormalizedDistance:distance inApplication:self.application]; } @@ -95,7 +87,8 @@ - (BOOL)fb_scrollToVisibleWithError:(NSError **)error return [self fb_scrollToVisibleWithNormalizedScrollDistance:FBScrollToVisibleNormalizedDistance error:error]; } -- (BOOL)fb_scrollToVisibleWithNormalizedScrollDistance:(CGFloat)normalizedScrollDistance error:(NSError **)error +- (BOOL)fb_scrollToVisibleWithNormalizedScrollDistance:(CGFloat)normalizedScrollDistance + error:(NSError **)error { return [self fb_scrollToVisibleWithNormalizedScrollDistance:normalizedScrollDistance scrollDirection:FBXCUIElementScrollDirectionUnknown @@ -106,7 +99,8 @@ - (BOOL)fb_scrollToVisibleWithNormalizedScrollDistance:(CGFloat)normalizedScroll scrollDirection:(FBXCUIElementScrollDirection)scrollDirection error:(NSError **)error { - FBXCElementSnapshotWrapper *prescrollSnapshot = [FBXCElementSnapshotWrapper ensureWrapped:[self fb_takeSnapshot]]; + FBXCElementSnapshotWrapper *prescrollSnapshot = [FBXCElementSnapshotWrapper ensureWrapped:[self fb_takeSnapshot:YES]]; + if (prescrollSnapshot.isWDVisible) { return YES; } @@ -138,12 +132,12 @@ - (BOOL)fb_scrollToVisibleWithNormalizedScrollDistance:(CGFloat)normalizedScroll FBXCElementSnapshotWrapper *wrappedCellSnapshot = [FBXCElementSnapshotWrapper ensureWrapped:cellSnapshot]; if (wrappedCellSnapshot.wdVisible) { [visibleCellSnapshots addObject:cellSnapshot]; + if (visibleCellSnapshots.count > 1) { + return YES; + } } } - if (visibleCellSnapshots.count > 1) { - return YES; - } return NO; }]; @@ -213,9 +207,9 @@ - (BOOL)fb_scrollToVisibleWithNormalizedScrollDistance:(CGFloat)normalizedScroll // Cell is now visible, but it might be only partialy visible, scrolling till whole frame is visible. // Sometimes, attempting to grab the parent snapshot of the target cell after scrolling is complete causes a stale element reference exception. // Trying fb_cachedSnapshot first - FBXCElementSnapshotWrapper *targetCellSnapshotWrapped = [FBXCElementSnapshotWrapper ensureWrapped:([self fb_cachedSnapshot] ?: [self fb_takeSnapshot])]; + FBXCElementSnapshotWrapper *targetCellSnapshotWrapped = [FBXCElementSnapshotWrapper ensureWrapped:[self fb_takeSnapshot:YES]]; targetCellSnapshot = [targetCellSnapshotWrapped fb_parentCellSnapshot]; - CGRect visibleFrame = [FBXCElementSnapshotWrapper ensureWrapped:targetCellSnapshot].fb_visibleFrameWithFallback; + CGRect visibleFrame = [FBXCElementSnapshotWrapper ensureWrapped:targetCellSnapshot].fb_visibleFrame; CGVector scrollVector = CGVectorMake(visibleFrame.size.width - targetCellSnapshot.frame.size.width, visibleFrame.size.height - targetCellSnapshot.frame.size.height @@ -233,7 +227,7 @@ - (BOOL)fb_isEquivalentElementSnapshotVisible:(id)snapshot return YES; } - id appSnapshot = [self.application fb_takeSnapshot]; + id appSnapshot = [self.application fb_takeSnapshot:YES]; for (id elementSnapshot in appSnapshot._allDescendants.copy) { FBXCElementSnapshotWrapper *wrappedElementSnapshot = [FBXCElementSnapshotWrapper ensureWrapped:elementSnapshot]; // We are comparing pre-scroll snapshot so frames are irrelevant. @@ -255,27 +249,32 @@ - (CGRect)scrollingFrame return self.visibleFrame; } -- (void)fb_scrollUpByNormalizedDistance:(CGFloat)distance inApplication:(XCUIApplication *)application +- (void)fb_scrollUpByNormalizedDistance:(CGFloat)distance + inApplication:(XCUIApplication *)application { [self fb_scrollByNormalizedVector:CGVectorMake(0.0, distance) inApplication:application]; } -- (void)fb_scrollDownByNormalizedDistance:(CGFloat)distance inApplication:(XCUIApplication *)application +- (void)fb_scrollDownByNormalizedDistance:(CGFloat)distance + inApplication:(XCUIApplication *)application { [self fb_scrollByNormalizedVector:CGVectorMake(0.0, -distance) inApplication:application]; } -- (void)fb_scrollLeftByNormalizedDistance:(CGFloat)distance inApplication:(XCUIApplication *)application +- (void)fb_scrollLeftByNormalizedDistance:(CGFloat)distance + inApplication:(XCUIApplication *)application { [self fb_scrollByNormalizedVector:CGVectorMake(distance, 0.0) inApplication:application]; } -- (void)fb_scrollRightByNormalizedDistance:(CGFloat)distance inApplication:(XCUIApplication *)application +- (void)fb_scrollRightByNormalizedDistance:(CGFloat)distance + inApplication:(XCUIApplication *)application { [self fb_scrollByNormalizedVector:CGVectorMake(-distance, 0.0) inApplication:application]; } -- (BOOL)fb_scrollByNormalizedVector:(CGVector)normalizedScrollVector inApplication:(XCUIApplication *)application +- (BOOL)fb_scrollByNormalizedVector:(CGVector)normalizedScrollVector + inApplication:(XCUIApplication *)application { CGVector scrollVector = CGVectorMake(CGRectGetWidth(self.scrollingFrame) * normalizedScrollVector.dx, CGRectGetHeight(self.scrollingFrame) * normalizedScrollVector.dy @@ -283,7 +282,9 @@ - (BOOL)fb_scrollByNormalizedVector:(CGVector)normalizedScrollVector inApplicati return [self fb_scrollByVector:scrollVector inApplication:application error:nil]; } -- (BOOL)fb_scrollByVector:(CGVector)vector inApplication:(XCUIApplication *)application error:(NSError **)error +- (BOOL)fb_scrollByVector:(CGVector)vector + inApplication:(XCUIApplication *)application + error:(NSError **)error { CGVector scrollBoundingVector = CGVectorMake( CGRectGetWidth(self.scrollingFrame) * FBScrollTouchProportion, @@ -314,7 +315,9 @@ - (CGVector)fb_hitPointOffsetForScrollingVector:(CGVector)scrollingVector return CGVectorMake((CGFloat)floor(x), (CGFloat)floor(y)); } -- (BOOL)fb_scrollAncestorScrollViewByVectorWithinScrollViewFrame:(CGVector)vector inApplication:(XCUIApplication *)application error:(NSError **)error +- (BOOL)fb_scrollAncestorScrollViewByVectorWithinScrollViewFrame:(CGVector)vector + inApplication:(XCUIApplication *)application + error:(NSError **)error { CGVector hitpointOffset = [self fb_hitPointOffsetForScrollingVector:vector]; diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBTyping.m b/WebDriverAgentLib/Categories/XCUIElement+FBTyping.m index 8b59ad031..4ea5cc66a 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBTyping.m +++ b/WebDriverAgentLib/Categories/XCUIElement+FBTyping.m @@ -91,7 +91,7 @@ - (void)fb_prepareForTextInputWithSnapshot:(FBXCElementSnapshotWrapper *)snapsho [FBLogger logFmt:@"Trying to tap the \"%@\" element to have it focused", snapshot.fb_description]; [self tap]; // It might take some time to update the UI - [self fb_takeSnapshot]; + [self fb_takeSnapshot:NO]; #endif } @@ -110,9 +110,7 @@ - (BOOL)fb_typeText:(NSString *)text frequency:(NSUInteger)frequency error:(NSError **)error { - id snapshot = self.fb_isResolvedFromCache.boolValue - ? self.lastSnapshot - : self.fb_takeSnapshot; + id snapshot = [self fb_takeSnapshot:NO]; FBXCElementSnapshotWrapper *wrapped = [FBXCElementSnapshotWrapper ensureWrapped:snapshot]; [self fb_prepareForTextInputWithSnapshot:wrapped]; if (shouldClear && ![self fb_clearTextWithSnapshot:wrapped shouldPrepareForInput:NO error:error]) { @@ -123,9 +121,7 @@ - (BOOL)fb_typeText:(NSString *)text - (BOOL)fb_clearTextWithError:(NSError **)error { - id snapshot = self.fb_isResolvedFromCache.boolValue - ? self.lastSnapshot - : self.fb_takeSnapshot; + id snapshot = [self fb_takeSnapshot:NO]; return [self fb_clearTextWithSnapshot:[FBXCElementSnapshotWrapper ensureWrapped:snapshot] shouldPrepareForInput:YES error:error]; @@ -182,7 +178,7 @@ - (BOOL)fb_clearTextWithSnapshot:(FBXCElementSnapshotWrapper *)snapshot return NO; } - currentValue = self.fb_takeSnapshot.value; + currentValue = [self fb_takeSnapshot:NO].value; if (nil != placeholderValue && [currentValue isEqualToString:placeholderValue]) { // Short circuit if only the placeholder value left return YES; diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBUID.m b/WebDriverAgentLib/Categories/XCUIElement+FBUID.m index ecac2cd91..70cfd4970 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBUID.m +++ b/WebDriverAgentLib/Categories/XCUIElement+FBUID.m @@ -22,14 +22,14 @@ - (unsigned long long)fb_accessibiltyId { return [FBElementUtils idWithAccessibilityElement:([self isKindOfClass:XCUIApplication.class] ? [(XCUIApplication *)self accessibilityElement] - : [self fb_takeSnapshot].accessibilityElement)]; + : [self fb_takeSnapshot:NO].accessibilityElement)]; } - (NSString *)fb_uid { return [self isKindOfClass:XCUIApplication.class] ? [FBElementUtils uidWithAccessibilityElement:[(XCUIApplication *)self accessibilityElement]] - : [FBXCElementSnapshotWrapper ensureWrapped:[self fb_takeSnapshot]].fb_uid; + : [FBXCElementSnapshotWrapper ensureWrapped:[self fb_takeSnapshot:NO]].fb_uid; } @end diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.h b/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.h index 66b9ee2c9..a16e581f4 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.h +++ b/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.h @@ -19,12 +19,13 @@ NS_ASSUME_NONNULL_BEGIN Gets the most recent snapshot of the current element. The element will be automatically resolved if the snapshot is not available yet. Calls to this method mutate the `lastSnapshot` instance property.. - Calls to this method reset the `fb_isResolvedFromCache` property value to `NO`. + @param inDepth Whether to resolve snapshot parents and children. Setting it to NO + would improve the snapshotting performance @return The recent snapshot of the element @throws FBStaleElementException if the element is not present in DOM and thus no snapshot could be made */ -- (id)fb_takeSnapshot; +- (id)fb_takeSnapshot:(BOOL)inDepth; /** Extracts the cached element snapshot from its query. @@ -36,40 +37,6 @@ NS_ASSUME_NONNULL_BEGIN */ - (nullable id)fb_cachedSnapshot; -/** - Gets the most recent snapshot of the current element and already resolves the accessibility attributes - needed for creating the page source of this element. No additional calls to the accessibility layer - are required. - Calls to this method mutate the `lastSnapshot` instance property. - Calls to this method reset the `fb_isResolvedFromCache` property value to `NO`. - - @param maxDepth The maximum depth of the snapshot. nil value means to use the default depth. - with custom attributes cannot be resolved - - @return The recent snapshot of the element with all attributes resolved or a snapshot with default - attributes resolved if there was a failure while resolving additional attributes - @throws FBStaleElementException if the element is not present in DOM and thus no snapshot could be made - */ -- (nullable id)fb_snapshotWithAllAttributesAndMaxDepth:(nullable NSNumber *)maxDepth; - -/** - Gets the most recent snapshot of the current element with given attributes resolved. - No additional calls to the accessibility layer are required. - Calls to this method mutate the `lastSnapshot` instance property. - Calls to this method reset the `fb_isResolvedFromCache` property value to `NO`. - - @param attributeNames The list of attribute names to resolve. Must be one of - FB_...Name values exported by XCTestPrivateSymbols.h module. - `nil` value means that only the default attributes must be extracted - @param maxDepth The maximum depth of the snapshot. nil value means to use the default depth. - - @return The recent snapshot of the element with the given attributes resolved or a snapshot with default - attributes resolved if there was a failure while resolving additional attributes - @throws FBStaleElementException if the element is not present in DOM and thus no snapshot could be made -*/ -- (nullable id)fb_snapshotWithAttributes:(nullable NSArray *)attributeNames - maxDepth:(nullable NSNumber *)maxDepth; - /** Filters elements by matching them to snapshots from the corresponding array diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m b/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m index 5f9fd96f4..7b6d52c03 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m +++ b/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m @@ -14,6 +14,7 @@ #import "FBConfiguration.h" #import "FBExceptions.h" #import "FBImageUtils.h" +#import "FBElementUtils.h" #import "FBLogger.h" #import "FBMacros.h" #import "FBMathUtils.h" @@ -32,6 +33,7 @@ #import "XCTestPrivateSymbols.h" #import "XCTRunnerDaemonSession.h" #import "XCUIApplicationProcess+FBQuiescence.h" +#import "XCUIApplication.h" #import "XCUIElement+FBCaching.h" #import "XCUIElement+FBWebDriverAttributes.h" #import "XCUIElementQuery.h" @@ -40,22 +42,21 @@ #import "XCUIScreen.h" #import "XCUIElement+FBResolve.h" -#define DEFAULT_AX_TIMEOUT 60. - @implementation XCUIElement (FBUtilities) -- (id)fb_takeSnapshot +- (id)fb_takeSnapshot:(BOOL)inDepth { NSError *error = nil; - self.fb_isResolvedFromCache = @(NO); - self.lastSnapshot = [self.fb_query fb_uniqueSnapshotWithError:&error]; + self.lastSnapshot = inDepth + ? [self.fb_query fb_uniqueSnapshotWithError:&error] + : (id)[self snapshotWithError:&error]; if (nil == self.lastSnapshot) { NSString *hintText = @"Make sure the application UI has the expected state"; - if (nil != error - && [error.localizedDescription containsString:@"Identity Binding"]) { + if (nil != error && [error.localizedDescription containsString:@"Identity Binding"]) { hintText = [NSString stringWithFormat:@"%@. You could also try to switch the binding strategy using the 'boundElementsByIndex' setting for the element lookup", hintText]; } - NSString *reason = [NSString stringWithFormat:@"The previously found element \"%@\" is not present in the current view anymore. %@", self.description, hintText]; + NSString *reason = [NSString stringWithFormat:@"The previously found element \"%@\" is not present in the current view anymore. %@", + self.description, hintText]; if (nil != error) { reason = [NSString stringWithFormat:@"%@. Original error: %@", reason, error.localizedDescription]; } @@ -69,63 +70,6 @@ @implementation XCUIElement (FBUtilities) return [self.query fb_cachedSnapshot]; } -- (nullable id)fb_snapshotWithAllAttributesAndMaxDepth:(NSNumber *)maxDepth -{ - NSMutableArray *allNames = [NSMutableArray arrayWithArray:FBStandardAttributeNames()]; - [allNames addObjectsFromArray:FBCustomAttributeNames()]; - return [self fb_snapshotWithAttributes:allNames.copy - maxDepth:maxDepth]; -} - -- (nullable id)fb_snapshotWithAttributes:(NSArray *)attributeNames - maxDepth:(NSNumber *)maxDepth -{ - NSSet *standardAttributes = [NSSet setWithArray:FBStandardAttributeNames()]; - id snapshot = self.fb_takeSnapshot; - NSTimeInterval axTimeout = FBConfiguration.customSnapshotTimeout; - if (nil == attributeNames - || [[NSSet setWithArray:attributeNames] isSubsetOfSet:standardAttributes] - || axTimeout < DBL_EPSILON) { - // return the "normal" element snapshot if no custom attributes are requested - return snapshot; - } - - id axElement = snapshot.accessibilityElement; - if (nil == axElement) { - return nil; - } - - NSError *setTimeoutError; - BOOL isTimeoutSet = [FBXCAXClientProxy.sharedClient setAXTimeout:axTimeout - error:&setTimeoutError]; - if (!isTimeoutSet) { - [FBLogger logFmt:@"Cannot set snapshoting timeout to %.1fs. Original error: %@", - axTimeout, setTimeoutError.localizedDescription]; - } - - NSError *error; - id snapshotWithAttributes = [FBXCAXClientProxy.sharedClient snapshotForElement:axElement - attributes:attributeNames - maxDepth:maxDepth - error:&error]; - if (nil == snapshotWithAttributes) { - NSString *description = [FBXCElementSnapshotWrapper ensureWrapped:snapshot].fb_description; - [FBLogger logFmt:@"Cannot take a snapshot with attribute(s) %@ of '%@' after %.2f seconds", - attributeNames, description, axTimeout]; - [FBLogger logFmt:@"This timeout could be customized via '%@' setting", FB_SETTING_CUSTOM_SNAPSHOT_TIMEOUT]; - [FBLogger logFmt:@"Internal error: %@", error.localizedDescription]; - [FBLogger logFmt:@"Falling back to the default snapshotting mechanism for the element '%@' (some attribute values, like visibility or accessibility might not be precise though)", description]; - snapshotWithAttributes = self.lastSnapshot; - } else { - self.lastSnapshot = snapshotWithAttributes; - } - - if (isTimeoutSet) { - [FBXCAXClientProxy.sharedClient setAXTimeout:DEFAULT_AX_TIMEOUT error:nil]; - } - return snapshotWithAttributes; -} - - (NSArray *)fb_filterDescendantsWithSnapshots:(NSArray> *)snapshots selfUID:(NSString *)selfUID onlyChildren:(BOOL)onlyChildren @@ -143,9 +87,7 @@ @implementation XCUIElement (FBUtilities) NSMutableArray *matchedElements = [NSMutableArray array]; NSString *uid = selfUID; if (nil == uid) { - uid = self.fb_isResolvedFromCache.boolValue - ? [FBXCElementSnapshotWrapper wdUIDWithSnapshot:self.lastSnapshot] - : self.fb_uid; + uid = self.fb_uid; } if (nil != uid && [matchedIds containsObject:uid]) { XCUIElement *stableSelf = self.fb_stableInstance; diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBVisibleFrame.h b/WebDriverAgentLib/Categories/XCUIElement+FBVisibleFrame.h new file mode 100644 index 000000000..8917275d1 --- /dev/null +++ b/WebDriverAgentLib/Categories/XCUIElement+FBVisibleFrame.h @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "FBXCElementSnapshotWrapper.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface XCUIElement (FBVisibleFrame) + +/** + Returns the snapshot visibleFrame with a fallback to direct attribute retrieval from FBXCAXClient in case of a snapshot fault (nil visibleFrame) + + @return the snapshot visibleFrame + */ +- (CGRect)fb_visibleFrame; + +@end + +@interface FBXCElementSnapshotWrapper (FBVisibleFrame) + +/** + Returns the snapshot visibleFrame with a fallback to direct attribute retrieval from FBXCAXClient in case of a snapshot fault (nil visibleFrame) + + @return the snapshot visibleFrame + */ +- (CGRect)fb_visibleFrame; + +@end + +NS_ASSUME_NONNULL_END diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBVisibleFrame.m b/WebDriverAgentLib/Categories/XCUIElement+FBVisibleFrame.m new file mode 100644 index 000000000..3117b4acb --- /dev/null +++ b/WebDriverAgentLib/Categories/XCUIElement+FBVisibleFrame.m @@ -0,0 +1,53 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "XCUIElement+FBVisibleFrame.h" +#import "FBElementUtils.h" +#import "FBXCodeCompatibility.h" +#import "FBXCElementSnapshotWrapper+Helpers.h" +#import "XCUIElement+FBUtilities.h" +#import "XCTestPrivateSymbols.h" + +@implementation XCUIElement (FBVisibleFrame) + +- (CGRect)fb_visibleFrame +{ + id snapshot = [self fb_takeSnapshot:NO]; + return [FBXCElementSnapshotWrapper ensureWrapped:snapshot].fb_visibleFrame; +} + +@end + +@implementation FBXCElementSnapshotWrapper (FBVisibleFrame) + +- (CGRect)fb_visibleFrame +{ + CGRect thisVisibleFrame = [self visibleFrame]; + if (!CGRectIsEmpty(thisVisibleFrame)) { + return thisVisibleFrame; + } + + NSDictionary *visibleFrameDict = [self fb_attributeValue:FB_XCAXAVisibleFrameAttributeName + error:nil]; + if (nil == visibleFrameDict) { + return thisVisibleFrame; + } + + id x = [visibleFrameDict objectForKey:@"X"]; + id y = [visibleFrameDict objectForKey:@"Y"]; + id height = [visibleFrameDict objectForKey:@"Height"]; + id width = [visibleFrameDict objectForKey:@"Width"]; + if (x != nil && y != nil && height != nil && width != nil) { + return CGRectMake([x doubleValue], [y doubleValue], [width doubleValue], [height doubleValue]); + } + + return thisVisibleFrame; +} + +@end diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBWebDriverAttributes.m b/WebDriverAgentLib/Categories/XCUIElement+FBWebDriverAttributes.m index b29c5a8b2..f99158c7f 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBWebDriverAttributes.m +++ b/WebDriverAgentLib/Categories/XCUIElement+FBWebDriverAttributes.m @@ -28,24 +28,10 @@ @implementation XCUIElement (WebDriverAttributesForwarding) - (id)fb_snapshotForAttributeName:(NSString *)name { - // These attributes are special, because we can only retrieve them from - // the snapshot if we explicitly ask XCTest to include them into the query while taking it. - // That is why fb_snapshotWithAllAttributes method must be used instead of the default snapshot - // call - if ([name isEqualToString:FBStringify(XCUIElement, isWDVisible)]) { - return [self fb_snapshotWithAttributes:@[FB_XCAXAIsVisibleAttributeName] - maxDepth:@1]; - } - if ([name isEqualToString:FBStringify(XCUIElement, isWDAccessible)]) { - return [self fb_snapshotWithAttributes:@[FB_XCAXAIsElementAttributeName] - maxDepth:@1]; - } - if ([name isEqualToString:FBStringify(XCUIElement, isWDAccessibilityContainer)]) { - return [self fb_snapshotWithAttributes:@[FB_XCAXAIsElementAttributeName] - maxDepth:nil]; - } - - return self.fb_takeSnapshot; + BOOL inDepth = [name isEqualToString:FBStringify(XCUIElement, isWDAccessible)] + || [name isEqualToString:FBStringify(XCUIElement, isWDAccessibilityContainer)] + || [name isEqualToString:FBStringify(XCUIElement, wdIndex)]; + return [self fb_takeSnapshot:inDepth]; } - (id)fb_valueForWDAttributeName:(NSString *)name @@ -92,6 +78,7 @@ - (NSString *)wdValue value = @([value boolValue]); } else if (elementType == XCUIElementTypeTextView || elementType == XCUIElementTypeTextField || + elementType == XCUIElementTypeSearchField || elementType == XCUIElementTypeSecureTextField) { NSString *placeholderValue = self.placeholderValue; value = FBFirstNonEmptyValue(value, placeholderValue); @@ -183,8 +170,8 @@ - (BOOL)isWDAccessible // In the scenario when table provides Search results controller, table could be marked as accessible element, even though it isn't // As it is highly unlikely that table view should ever be an accessibility element itself, // for now we work around that by skipping Table View in container checks - if ([FBXCElementSnapshotWrapper ensureWrapped:parentSnapshot].fb_isAccessibilityElement - && parentSnapshot.elementType != XCUIElementTypeTable) { + if (parentSnapshot.elementType != XCUIElementTypeTable + && [FBXCElementSnapshotWrapper ensureWrapped:parentSnapshot].fb_isAccessibilityElement) { return NO; } parentSnapshot = parentSnapshot.parent; diff --git a/WebDriverAgentLib/Commands/FBCustomCommands.m b/WebDriverAgentLib/Commands/FBCustomCommands.m index 2ab039e6b..97ecfbca9 100644 --- a/WebDriverAgentLib/Commands/FBCustomCommands.m +++ b/WebDriverAgentLib/Commands/FBCustomCommands.m @@ -567,7 +567,8 @@ + (NSString *)timeZone FBElementCache *elementCache = request.session.elementCache; BOOL hasElement = ![request.parameters[@"uuid"] isEqual:@"0"]; XCUIElement *destination = hasElement - ? [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]] + ? [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"] + checkStaleness:YES] : request.session.activeApplication; id keys = request.arguments[@"keys"]; diff --git a/WebDriverAgentLib/Commands/FBElementCommands.m b/WebDriverAgentLib/Commands/FBElementCommands.m index 762bad327..79fa30b8d 100644 --- a/WebDriverAgentLib/Commands/FBElementCommands.m +++ b/WebDriverAgentLib/Commands/FBElementCommands.m @@ -126,38 +126,22 @@ + (NSArray *)routes { FBElementCache *elementCache = request.session.elementCache; XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]]; - BOOL isEnabled = [FBXCElementSnapshotWrapper ensureWrapped:element.lastSnapshot].isWDEnabled; - return FBResponseWithObject(isEnabled ? @YES : @NO); + return FBResponseWithObject(@(element.isWDEnabled)); } + (id)handleGetRect:(FBRouteRequest *)request { FBElementCache *elementCache = request.session.elementCache; XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]]; - return FBResponseWithObject([FBXCElementSnapshotWrapper ensureWrapped:element.lastSnapshot].wdRect); + return FBResponseWithObject(element.wdRect); } + (id)handleGetAttribute:(FBRouteRequest *)request { FBElementCache *elementCache = request.session.elementCache; NSString *attributeName = request.parameters[@"name"]; - NSString *wdAttributeName = [FBElementUtils wdAttributeNameForAttributeName:attributeName]; - NSArray *additionalAttributes = nil; - NSNumber *maxDepth = nil; - if ([wdAttributeName isEqualToString:FBStringify(XCUIElement, isWDVisible)]) { - additionalAttributes = @[FB_XCAXAIsVisibleAttributeName]; - maxDepth = @1; - } else if ([wdAttributeName isEqualToString:FBStringify(XCUIElement, isWDEnabled)]) { - additionalAttributes = @[FB_XCAXAIsElementAttributeName]; - maxDepth = @1; - } else if ([wdAttributeName isEqualToString:FBStringify(XCUIElement, isWDAccessibilityContainer)]) { - additionalAttributes = @[FB_XCAXAIsElementAttributeName]; - } - XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"] - resolveForAdditionalAttributes:additionalAttributes - andMaxDepth:maxDepth]; - FBXCElementSnapshotWrapper *wrappedSnapshot = [FBXCElementSnapshotWrapper ensureWrapped:element.lastSnapshot]; - id attributeValue = [wrappedSnapshot fb_valueForWDAttributeName:attributeName]; + XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]]; + id attributeValue = [element fb_valueForWDAttributeName:attributeName]; return FBResponseWithObject(attributeValue ?: [NSNull null]); } @@ -165,7 +149,7 @@ + (NSArray *)routes { FBElementCache *elementCache = request.session.elementCache; XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]]; - FBXCElementSnapshotWrapper *wrappedSnapshot = [FBXCElementSnapshotWrapper ensureWrapped:element.lastSnapshot]; + FBXCElementSnapshotWrapper *wrappedSnapshot = [FBXCElementSnapshotWrapper ensureWrapped:[element fb_takeSnapshot:NO]]; id text = FBFirstNonEmptyValue(wrappedSnapshot.wdValue, wrappedSnapshot.wdLabel); return FBResponseWithObject(text ?: @""); } @@ -173,48 +157,43 @@ + (NSArray *)routes + (id)handleGetDisplayed:(FBRouteRequest *)request { FBElementCache *elementCache = request.session.elementCache; - XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"] - resolveForAdditionalAttributes:@[FB_XCAXAIsVisibleAttributeName] - andMaxDepth:@1]; - return FBResponseWithObject(@([FBXCElementSnapshotWrapper ensureWrapped:element.lastSnapshot].isWDVisible)); + XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]]; + return FBResponseWithObject(@(element.isWDVisible)); } + (id)handleGetAccessible:(FBRouteRequest *)request { FBElementCache *elementCache = request.session.elementCache; - XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"] - resolveForAdditionalAttributes:@[FB_XCAXAIsElementAttributeName] - andMaxDepth:@1]; - return FBResponseWithObject(@([FBXCElementSnapshotWrapper ensureWrapped:element.lastSnapshot].isWDAccessible)); + XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]]; + return FBResponseWithObject(@(element.isWDAccessible)); } + (id)handleGetIsAccessibilityContainer:(FBRouteRequest *)request { FBElementCache *elementCache = request.session.elementCache; - XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"] - resolveForAdditionalAttributes:@[FB_XCAXAIsElementAttributeName] - andMaxDepth:nil]; - return FBResponseWithObject(@([FBXCElementSnapshotWrapper ensureWrapped:element.lastSnapshot].isWDAccessibilityContainer)); + XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]]; + return FBResponseWithObject(@(element.isWDAccessibilityContainer)); } + (id)handleGetName:(FBRouteRequest *)request { FBElementCache *elementCache = request.session.elementCache; XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]]; - return FBResponseWithObject([FBXCElementSnapshotWrapper ensureWrapped:element.lastSnapshot].wdType); + return FBResponseWithObject(element.wdType); } + (id)handleGetSelected:(FBRouteRequest *)request { FBElementCache *elementCache = request.session.elementCache; XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]]; - return FBResponseWithObject(@([FBXCElementSnapshotWrapper ensureWrapped:element.lastSnapshot].wdSelected)); + return FBResponseWithObject(@(element.wdSelected)); } + (id)handleSetValue:(FBRouteRequest *)request { FBElementCache *elementCache = request.session.elementCache; - XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]]; + XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"] + checkStaleness:YES]; id value = request.arguments[@"value"] ?: request.arguments[@"text"]; if (!value) { return FBResponseWithStatus([FBCommandStatus invalidArgumentErrorWithMessage:@"Neither 'value' nor 'text' parameter is provided" traceback:nil]); @@ -222,7 +201,7 @@ + (NSArray *)routes NSString *textToType = [value isKindOfClass:NSArray.class] ? [value componentsJoinedByString:@""] : value; - XCUIElementType elementType = [(id)element.lastSnapshot elementType]; + XCUIElementType elementType = [element elementType]; #if !TARGET_OS_TV if (elementType == XCUIElementTypePickerWheel) { [element adjustToPickerWheelValue:textToType]; @@ -251,7 +230,7 @@ + (NSArray *)routes + (id)handleClick:(FBRouteRequest *)request { FBElementCache *elementCache = request.session.elementCache; - XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]]; + XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"] checkStaleness:YES]; #if TARGET_OS_IOS [element tap]; #elif TARGET_OS_TV @@ -353,7 +332,7 @@ + (NSArray *)routes FBElementCache *elementCache = request.session.elementCache; XCUIElement *element = [self targetFromRequest:request]; [element pressForDuration:[request.arguments[@"pressDuration"] doubleValue] - thenDragToElement:[elementCache elementForUUID:(NSString *)request.arguments[@"toElement"]] + thenDragToElement:[elementCache elementForUUID:(NSString *)request.arguments[@"toElement"] checkStaleness:YES] withVelocity:[request.arguments[@"velocity"] doubleValue] thenHoldForDuration:[request.arguments[@"holdDuration"] doubleValue]]; return FBResponseWithOK(); @@ -441,10 +420,7 @@ + (NSArray *)routes + (id)handleDrag:(FBRouteRequest *)request { - NSString *elementUdid = (NSString *)request.parameters[@"uuid"]; - XCUIElement *target = nil == elementUdid - ? request.session.activeApplication - : [request.session.elementCache elementForUUID:elementUdid]; + XCUIElement *target = [self targetFromRequest:request]; CGVector startOffset = CGVectorMake([request.arguments[@"fromX"] doubleValue], [request.arguments[@"fromY"] doubleValue]); XCUICoordinate *startCoordinate = [self.class gestureCoordinateWithOffset:startOffset element:target]; @@ -561,7 +537,8 @@ + (NSArray *)routes + (id)handleElementScreenshot:(FBRouteRequest *)request { FBElementCache *elementCache = request.session.elementCache; - XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]]; + XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"] + checkStaleness:YES]; NSData *screenshotData = [element.screenshot PNGRepresentation]; if (nil == screenshotData) { NSString *errMsg = [NSString stringWithFormat:@"Cannot take a screenshot of %@", element.description]; @@ -581,8 +558,9 @@ + (NSArray *)routes + (id)handleWheelSelect:(FBRouteRequest *)request { FBElementCache *elementCache = request.session.elementCache; - XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]]; - if ([element.lastSnapshot elementType] != XCUIElementTypePickerWheel) { + XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"] + checkStaleness:YES]; + if ([element elementType] != XCUIElementTypePickerWheel) { NSString *errMsg = [NSString stringWithFormat:@"The element is expected to be a valid Picker Wheel control. '%@' was given instead", element.wdType]; return FBResponseWithStatus([FBCommandStatus invalidArgumentErrorWithMessage:errMsg traceback:[NSString stringWithFormat:@"%@", NSThread.callStackSymbols]]); @@ -688,7 +666,7 @@ + (XCUIElement *)targetFromRequest:(FBRouteRequest *)request NSString *elementUuid = (NSString *)request.parameters[@"uuid"]; return nil == elementUuid ? request.session.activeApplication - : [elementCache elementForUUID:elementUuid]; + : [elementCache elementForUUID:elementUuid checkStaleness:YES]; } #endif diff --git a/WebDriverAgentLib/Commands/FBFindElementCommands.m b/WebDriverAgentLib/Commands/FBFindElementCommands.m index ba30a7170..a92c5082e 100644 --- a/WebDriverAgentLib/Commands/FBFindElementCommands.m +++ b/WebDriverAgentLib/Commands/FBFindElementCommands.m @@ -80,15 +80,14 @@ + (NSArray *)routes + (id)handleFindVisibleCells:(FBRouteRequest *)request { FBElementCache *elementCache = request.session.elementCache; - XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"] - resolveForAdditionalAttributes:@[FB_XCAXAIsVisibleAttributeName] - andMaxDepth:nil]; - NSArray> *visibleCellSnapshots = [element.lastSnapshot descendantsByFilteringWithBlock:^BOOL(id snapshot) { - return snapshot.elementType == XCUIElementTypeCell - && [FBXCElementSnapshotWrapper ensureWrapped:snapshot].wdVisible; + XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]]; + id snapshot = [element fb_takeSnapshot:YES]; + NSArray> *visibleCellSnapshots = [snapshot descendantsByFilteringWithBlock:^BOOL(id shot) { + return shot.elementType == XCUIElementTypeCell + && [FBXCElementSnapshotWrapper ensureWrapped:shot].wdVisible; }]; NSArray *cells = [element fb_filterDescendantsWithSnapshots:visibleCellSnapshots - selfUID:[FBXCElementSnapshotWrapper wdUIDWithSnapshot:element.lastSnapshot] + selfUID:[FBXCElementSnapshotWrapper wdUIDWithSnapshot:snapshot] onlyChildren:NO]; return FBResponseWithCachedElements(cells, request.session.elementCache, FBConfiguration.shouldUseCompactResponses); } @@ -96,7 +95,8 @@ + (NSArray *)routes + (id)handleFindSubElement:(FBRouteRequest *)request { FBElementCache *elementCache = request.session.elementCache; - XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]]; + XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"] + checkStaleness:YES]; XCUIElement *foundElement = [self.class elementUsing:request.arguments[@"using"] withValue:request.arguments[@"value"] under:element]; @@ -109,7 +109,8 @@ + (NSArray *)routes + (id)handleFindSubElements:(FBRouteRequest *)request { FBElementCache *elementCache = request.session.elementCache; - XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]]; + XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"] + checkStaleness:YES]; NSArray *foundElements = [self.class elementsUsing:request.arguments[@"using"] withValue:request.arguments[@"value"] under:element diff --git a/WebDriverAgentLib/Commands/FBSessionCommands.m b/WebDriverAgentLib/Commands/FBSessionCommands.m index 1972186d2..8f84d7afe 100644 --- a/WebDriverAgentLib/Commands/FBSessionCommands.m +++ b/WebDriverAgentLib/Commands/FBSessionCommands.m @@ -336,7 +336,6 @@ + (NSArray *)routes FB_SETTING_SCREENSHOT_QUALITY: @([FBConfiguration screenshotQuality]), FB_SETTING_KEYBOARD_AUTOCORRECTION: @([FBConfiguration keyboardAutocorrection]), FB_SETTING_KEYBOARD_PREDICTION: @([FBConfiguration keyboardPrediction]), - FB_SETTING_CUSTOM_SNAPSHOT_TIMEOUT: @([FBConfiguration customSnapshotTimeout]), FB_SETTING_SNAPSHOT_MAX_DEPTH: @([FBConfiguration snapshotMaxDepth]), FB_SETTING_USE_FIRST_MATCH: @([FBConfiguration useFirstMatch]), FB_SETTING_WAIT_FOR_IDLE_TIMEOUT: @([FBConfiguration waitForIdleTimeout]), @@ -395,13 +394,6 @@ + (NSArray *)routes if (nil != [settings objectForKey:FB_SETTING_RESPECT_SYSTEM_ALERTS]) { [FBConfiguration setShouldRespectSystemAlerts:[[settings objectForKey:FB_SETTING_RESPECT_SYSTEM_ALERTS] boolValue]]; } - // SNAPSHOT_TIMEOUT setting is deprecated. Please use CUSTOM_SNAPSHOT_TIMEOUT instead - if (nil != [settings objectForKey:FB_SETTING_SNAPSHOT_TIMEOUT]) { - [FBConfiguration setCustomSnapshotTimeout:[[settings objectForKey:FB_SETTING_SNAPSHOT_TIMEOUT] doubleValue]]; - } - if (nil != [settings objectForKey:FB_SETTING_CUSTOM_SNAPSHOT_TIMEOUT]) { - [FBConfiguration setCustomSnapshotTimeout:[[settings objectForKey:FB_SETTING_CUSTOM_SNAPSHOT_TIMEOUT] doubleValue]]; - } if (nil != [settings objectForKey:FB_SETTING_SNAPSHOT_MAX_DEPTH]) { [FBConfiguration setSnapshotMaxDepth:[[settings objectForKey:FB_SETTING_SNAPSHOT_MAX_DEPTH] intValue]]; } diff --git a/WebDriverAgentLib/FBAlert.m b/WebDriverAgentLib/FBAlert.m index b06e26788..aca9781e1 100644 --- a/WebDriverAgentLib/FBAlert.m +++ b/WebDriverAgentLib/FBAlert.m @@ -50,7 +50,7 @@ - (BOOL)isPresent if (nil == self.alertElement) { return NO; } - [self.alertElement fb_takeSnapshot]; + [self.alertElement fb_takeSnapshot:YES]; return YES; } @catch (NSException *) { return NO; @@ -82,7 +82,7 @@ - (NSString *)text } NSMutableArray *resultText = [NSMutableArray array]; - id snapshot = self.alertElement.lastSnapshot; + id snapshot = self.alertElement.lastSnapshot ?: [self.alertElement fb_takeSnapshot:YES]; BOOL isSafariAlert = [self.class isSafariWebAlertWithSnapshot:snapshot]; [snapshot enumerateDescendantsUsingBlock:^(id descendant) { XCUIElementType elementType = descendant.elementType; @@ -145,7 +145,8 @@ - (NSArray *)buttonLabels } NSMutableArray *labels = [NSMutableArray array]; - [self.alertElement.lastSnapshot enumerateDescendantsUsingBlock:^(id descendant) { + id alertSnapshot = self.alertElement.lastSnapshot ?: [self.alertElement fb_takeSnapshot:YES]; + [alertSnapshot enumerateDescendantsUsingBlock:^(id descendant) { if (descendant.elementType != XCUIElementTypeButton) { return; } @@ -163,7 +164,7 @@ - (BOOL)acceptWithError:(NSError **)error return [self notPresentWithError:error]; } - id alertSnapshot = self.alertElement.lastSnapshot; + id alertSnapshot = self.alertElement.lastSnapshot ?: [self.alertElement fb_takeSnapshot:YES]; XCUIElement *acceptButton = nil; if (FBConfiguration.acceptAlertButtonSelector.length) { NSString *errorReason = nil; @@ -204,7 +205,7 @@ - (BOOL)dismissWithError:(NSError **)error return [self notPresentWithError:error]; } - id alertSnapshot = self.alertElement.lastSnapshot; + id alertSnapshot = self.alertElement.lastSnapshot ?: [self.alertElement fb_takeSnapshot:YES]; XCUIElement *dismissButton = nil; if (FBConfiguration.dismissAlertButtonSelector.length) { NSString *errorReason = nil; diff --git a/WebDriverAgentLib/Routing/FBElementCache.h b/WebDriverAgentLib/Routing/FBElementCache.h index 13100eeb2..940c2df6f 100644 --- a/WebDriverAgentLib/Routing/FBElementCache.h +++ b/WebDriverAgentLib/Routing/FBElementCache.h @@ -35,26 +35,20 @@ extern const int ELEMENT_CACHE_SIZE; @param uuid uuid of element to fetch @return element - @throws FBStaleElementException if the found element is not present in DOM anymore @throws FBInvalidArgumentException if uuid is nil */ - (XCUIElement *)elementForUUID:(NSString *)uuid; /** - Returns cached element + Returns cached element resolved with default snapshot attributes @param uuid uuid of element to fetch - @param additionalAttributes Add additonal attribute names if the snapshot should contain - them in `addtionalAttributes` section. nil value resolves the snapshot with standard attributes. - @param maxDepth The maximum depth of the snapshot. Only works if additional attributes are provided. - `nil` value means to use the default maximum depth value. + @param checkStaleness Whether to throw FBStaleElementException if the found element is not present in DOM anymore @return element - @throws FBStaleElementException if the found element is not present in DOM anymore + @throws FBStaleElementException if `checkStaleness` is enabled @throws FBInvalidArgumentException if uuid is nil */ -- (XCUIElement *)elementForUUID:(NSString *)uuid - resolveForAdditionalAttributes:(nullable NSArray *)additionalAttributes - andMaxDepth:(nullable NSNumber *)maxDepth; +- (XCUIElement *)elementForUUID:(NSString *)uuid checkStaleness:(BOOL)checkStaleness; /** Checks element existence in the cache diff --git a/WebDriverAgentLib/Routing/FBElementCache.m b/WebDriverAgentLib/Routing/FBElementCache.m index 1f069bec6..3228f752c 100644 --- a/WebDriverAgentLib/Routing/FBElementCache.m +++ b/WebDriverAgentLib/Routing/FBElementCache.m @@ -26,7 +26,6 @@ @interface FBElementCache () @property (nonatomic, strong) LRUCache *elementCache; -@property (nonatomic) BOOL elementsNeedReset; @end @implementation FBElementCache @@ -38,7 +37,6 @@ - (instancetype)init return nil; } _elementCache = [[LRUCache alloc] initWithCapacity:ELEMENT_CACHE_SIZE]; - _elementsNeedReset = NO; return self; } @@ -50,19 +48,16 @@ - (NSString *)storeElement:(XCUIElement *)element } @synchronized (self.elementCache) { [self.elementCache setObject:element forKey:uuid]; - self.elementsNeedReset = YES; } return uuid; } - (XCUIElement *)elementForUUID:(NSString *)uuid { - return [self elementForUUID:uuid resolveForAdditionalAttributes:nil andMaxDepth:nil]; + return [self elementForUUID:uuid checkStaleness:NO]; } -- (XCUIElement *)elementForUUID:(NSString *)uuid - resolveForAdditionalAttributes:(NSArray *)additionalAttributes - andMaxDepth:(NSNumber *)maxDepth +- (XCUIElement *)elementForUUID:(NSString *)uuid checkStaleness:(BOOL)checkStaleness { if (!uuid) { NSString *reason = [NSString stringWithFormat:@"Cannot extract cached element for UUID: %@", uuid]; @@ -71,23 +66,15 @@ - (XCUIElement *)elementForUUID:(NSString *)uuid XCUIElement *element; @synchronized (self.elementCache) { - [self resetElements]; element = [self.elementCache objectForKey:uuid]; } if (nil == element) { NSString *reason = [NSString stringWithFormat:@"The element identified by \"%@\" is either not present or it has expired from the internal cache. Try to find it again", uuid]; @throw [NSException exceptionWithName:FBStaleElementException reason:reason userInfo:@{}]; } - // This will throw FBStaleElementException exception if the element is stale - // or resolve the element and set lastSnapshot property - if (nil == additionalAttributes) { - [element fb_takeSnapshot]; - } else { - NSMutableArray *attributes = [NSMutableArray arrayWithArray:FBStandardAttributeNames()]; - [attributes addObjectsFromArray:additionalAttributes]; - [element fb_snapshotWithAttributes:attributes.copy maxDepth:maxDepth]; + if (checkStaleness) { + [element fb_takeSnapshot:NO]; } - element.fb_isResolvedFromCache = @(YES); return element; } @@ -101,20 +88,4 @@ - (BOOL)hasElementWithUUID:(NSString *)uuid } } -- (void)resetElements -{ - if (!self.elementsNeedReset) { - return; - } - - for (XCUIElement *element in self.elementCache.allObjects) { - element.lastSnapshot = nil; - if (nil != element.query) { - element.query.rootElementSnapshot = nil; - } - element.fb_isResolvedFromCache = @(NO); - } - self.elementsNeedReset = NO; -} - @end diff --git a/WebDriverAgentLib/Routing/FBResponsePayload.m b/WebDriverAgentLib/Routing/FBResponsePayload.m index 08fcd63fe..dcaa77403 100644 --- a/WebDriverAgentLib/Routing/FBResponsePayload.m +++ b/WebDriverAgentLib/Routing/FBResponsePayload.m @@ -91,13 +91,7 @@ inline NSDictionary *FBDictionaryResponseWithElement(XCUIElement *element, BOOL compact) { - id snapshot = nil; - if (nil != element.query.rootElementSnapshot) { - snapshot = element.fb_cachedSnapshot; - } - if (nil == snapshot) { - snapshot = element.lastSnapshot ?: element.fb_takeSnapshot; - } + id snapshot = element.lastSnapshot ?: element.fb_cachedSnapshot ?: [element fb_takeSnapshot:YES]; NSDictionary *compactResult = FBToElementDict((NSString *)[FBXCElementSnapshotWrapper wdUIDWithSnapshot:snapshot]); if (compact) { return compactResult; diff --git a/WebDriverAgentLib/Utilities/FBConfiguration.h b/WebDriverAgentLib/Utilities/FBConfiguration.h index 7c337826c..ad9687b19 100644 --- a/WebDriverAgentLib/Utilities/FBConfiguration.h +++ b/WebDriverAgentLib/Utilities/FBConfiguration.h @@ -177,14 +177,6 @@ typedef NS_ENUM(NSInteger, FBConfigurationKeyboardPreference) { + (void)setKeyboardPrediction:(BOOL)isEnabled; + (FBConfigurationKeyboardPreference)keyboardPrediction; -/** - * The maximum time to wait until accessibility snapshot is taken - * - * @param timeout The number of float seconds to wait (15 seconds by default) - */ -+ (void)setCustomSnapshotTimeout:(NSTimeInterval)timeout; -+ (NSTimeInterval)customSnapshotTimeout; - /** Sets maximum depth for traversing elements tree from parents to children while requesting XCElementSnapshot. Used to set maxDepth value in a dictionary provided by XCAXClient_iOS's method defaultParams. diff --git a/WebDriverAgentLib/Utilities/FBConfiguration.m b/WebDriverAgentLib/Utilities/FBConfiguration.m index dab8cb4db..1065b892e 100644 --- a/WebDriverAgentLib/Utilities/FBConfiguration.m +++ b/WebDriverAgentLib/Utilities/FBConfiguration.m @@ -46,7 +46,6 @@ static BOOL FBShouldTerminateApp; static NSNumber* FBMaxTypingFrequency; static NSUInteger FBScreenshotQuality; -static NSTimeInterval FBCustomSnapshotTimeout; static BOOL FBShouldUseFirstMatch; static BOOL FBShouldBoundElementsByIndex; static BOOL FBIncludeNonModalElements; @@ -359,16 +358,6 @@ + (void)setKeyboardPrediction:(BOOL)isEnabled [self configureKeyboardsPreference:isEnabled forPreferenceKey:FBKeyboardPredictionKey]; } -+ (void)setCustomSnapshotTimeout:(NSTimeInterval)timeout -{ - FBCustomSnapshotTimeout = timeout; -} - -+ (NSTimeInterval)customSnapshotTimeout -{ - return FBCustomSnapshotTimeout; -} - + (void)setSnapshotMaxDepth:(int)maxDepth { FBSetCustomParameterForElementSnapshot(FBSnapshotMaxDepthKey, @(maxDepth)); @@ -502,7 +491,6 @@ + (void)resetSessionSettings FBElementResponseAttributes = @"type,label"; FBMaxTypingFrequency = @([self defaultTypingFrequency]); FBScreenshotQuality = 3; - FBCustomSnapshotTimeout = 15.; FBShouldUseFirstMatch = NO; FBShouldBoundElementsByIndex = NO; // This is diabled by default because enabling it prevents the accessbility snapshot to be taken diff --git a/WebDriverAgentLib/Utilities/FBSettings.h b/WebDriverAgentLib/Utilities/FBSettings.h index b1f2f1fca..1a551c63f 100644 --- a/WebDriverAgentLib/Utilities/FBSettings.h +++ b/WebDriverAgentLib/Utilities/FBSettings.h @@ -22,9 +22,6 @@ extern NSString* const FB_SETTING_MJPEG_SCALING_FACTOR; extern NSString* const FB_SETTING_SCREENSHOT_QUALITY; extern NSString* const FB_SETTING_KEYBOARD_AUTOCORRECTION; extern NSString* const FB_SETTING_KEYBOARD_PREDICTION; -// This setting is deprecated. Please use CUSTOM_SNAPSHOT_TIMEOUT instead -extern NSString* const FB_SETTING_SNAPSHOT_TIMEOUT; -extern NSString* const FB_SETTING_CUSTOM_SNAPSHOT_TIMEOUT; extern NSString* const FB_SETTING_SNAPSHOT_MAX_DEPTH; extern NSString* const FB_SETTING_USE_FIRST_MATCH; extern NSString* const FB_SETTING_BOUND_ELEMENTS_BY_INDEX; diff --git a/WebDriverAgentLib/Utilities/FBSettings.m b/WebDriverAgentLib/Utilities/FBSettings.m index ada529eed..f5a61a8a8 100644 --- a/WebDriverAgentLib/Utilities/FBSettings.m +++ b/WebDriverAgentLib/Utilities/FBSettings.m @@ -18,8 +18,6 @@ NSString* const FB_SETTING_SCREENSHOT_QUALITY = @"screenshotQuality"; NSString* const FB_SETTING_KEYBOARD_AUTOCORRECTION = @"keyboardAutocorrection"; NSString* const FB_SETTING_KEYBOARD_PREDICTION = @"keyboardPrediction"; -NSString* const FB_SETTING_SNAPSHOT_TIMEOUT = @"snapshotTimeout"; -NSString* const FB_SETTING_CUSTOM_SNAPSHOT_TIMEOUT = @"customSnapshotTimeout"; NSString* const FB_SETTING_SNAPSHOT_MAX_DEPTH = @"snapshotMaxDepth"; NSString* const FB_SETTING_USE_FIRST_MATCH = @"useFirstMatch"; NSString* const FB_SETTING_BOUND_ELEMENTS_BY_INDEX = @"boundElementsByIndex"; diff --git a/WebDriverAgentLib/Utilities/FBTVNavigationTracker.m b/WebDriverAgentLib/Utilities/FBTVNavigationTracker.m index 11becfa72..4c42b1419 100644 --- a/WebDriverAgentLib/Utilities/FBTVNavigationTracker.m +++ b/WebDriverAgentLib/Utilities/FBTVNavigationTracker.m @@ -57,9 +57,7 @@ - (instancetype)initWithTargetElement:(XCUIElement *)targetElement self = [super init]; if (self) { _targetElement = targetElement; - CGRect frame = targetElement.fb_isResolvedFromCache.boolValue - ? [FBXCElementSnapshotWrapper ensureWrapped:targetElement.lastSnapshot].wdFrame - : targetElement.wdFrame; + CGRect frame = targetElement.wdFrame; _targetCenter = FBRectGetCenter(frame); _navigationItems = [NSMutableDictionary dictionary]; } diff --git a/WebDriverAgentLib/Utilities/FBW3CActionsSynthesizer.m b/WebDriverAgentLib/Utilities/FBW3CActionsSynthesizer.m index c488ca4ac..bd2dd3952 100644 --- a/WebDriverAgentLib/Utilities/FBW3CActionsSynthesizer.m +++ b/WebDriverAgentLib/Utilities/FBW3CActionsSynthesizer.m @@ -661,7 +661,7 @@ @implementation FBW3CActionsSynthesizer if ([origin isKindOfClass:XCUIElement.class]) { instance = origin; } else if ([origin isKindOfClass:NSString.class]) { - instance = [self.elementCache elementForUUID:(NSString *)origin]; + instance = [self.elementCache elementForUUID:(NSString *)origin checkStaleness:YES]; } else { [result addObject:actionItem]; continue; diff --git a/WebDriverAgentLib/Utilities/FBXCAXClientProxy.h b/WebDriverAgentLib/Utilities/FBXCAXClientProxy.h index cf6f497a9..45a8bcb34 100644 --- a/WebDriverAgentLib/Utilities/FBXCAXClientProxy.h +++ b/WebDriverAgentLib/Utilities/FBXCAXClientProxy.h @@ -27,7 +27,7 @@ NS_ASSUME_NONNULL_BEGIN - (nullable id)snapshotForElement:(id)element attributes:(nullable NSArray *)attributes - maxDepth:(nullable NSNumber *)maxDepth + inDepth:(BOOL)inDepth error:(NSError **)error; - (NSArray> *)activeApplications; @@ -39,8 +39,9 @@ NS_ASSUME_NONNULL_BEGIN - (void)notifyWhenNoAnimationsAreActiveForApplication:(XCUIApplication *)application reply:(void (^)(void))reply; -- (NSDictionary *)attributesForElement:(id)element - attributes:(NSArray *)attributes; +- (nullable NSDictionary *)attributesForElement:(id)element + attributes:(NSArray *)attributes + error:(NSError**)error; - (XCUIApplication *)monitoredApplicationWithProcessIdentifier:(int)pid; diff --git a/WebDriverAgentLib/Utilities/FBXCAXClientProxy.m b/WebDriverAgentLib/Utilities/FBXCAXClientProxy.m index 907bb25b1..4c7c9cf27 100644 --- a/WebDriverAgentLib/Utilities/FBXCAXClientProxy.m +++ b/WebDriverAgentLib/Utilities/FBXCAXClientProxy.m @@ -37,12 +37,12 @@ - (BOOL)setAXTimeout:(NSTimeInterval)timeout error:(NSError **)error - (id)snapshotForElement:(id)element attributes:(NSArray *)attributes - maxDepth:(nullable NSNumber *)maxDepth + inDepth:(BOOL)inDepth error:(NSError **)error { NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithDictionary:self.defaultParameters]; - if (nil != maxDepth) { - parameters[FBSnapshotMaxDepthKey] = maxDepth; + if (!inDepth) { + parameters[FBSnapshotMaxDepthKey] = @1; } id result = [FBAXClient requestSnapshotForElement:element @@ -76,15 +76,11 @@ - (void)notifyWhenNoAnimationsAreActiveForApplication:(XCUIApplication *)applica - (NSDictionary *)attributesForElement:(id)element attributes:(NSArray *)attributes + error:(NSError**)error; { - NSError *error = nil; - NSDictionary* result = [FBAXClient attributesForElement:element - attributes:attributes - error:&error]; - if (error) { - [FBLogger logFmt:@"Cannot retrieve element attribute(s) %@. Original error: %@", attributes, error.description]; - } - return result; + return [FBAXClient attributesForElement:element + attributes:attributes + error:error]; } - (XCUIApplication *)monitoredApplicationWithProcessIdentifier:(int)pid diff --git a/WebDriverAgentLib/Utilities/FBXCodeCompatibility.h b/WebDriverAgentLib/Utilities/FBXCodeCompatibility.h index 0a7dd9a0c..f00f2e0b1 100644 --- a/WebDriverAgentLib/Utilities/FBXCodeCompatibility.h +++ b/WebDriverAgentLib/Utilities/FBXCodeCompatibility.h @@ -10,6 +10,8 @@ #import #import "XCPointerEvent.h" +@class FBXCElementSnapshot; + /** The version of testmanagerd process which is running on the device. @@ -46,7 +48,7 @@ NS_ASSUME_NONNULL_BEGIN @param error The error instance if there was a failure while retrieveing the snapshot @returns The cached unqiue snapshot or nil if the element is stale */ -- (nullable XCElementSnapshot *)fb_uniqueSnapshotWithError:(NSError **)error; +- (nullable id)fb_uniqueSnapshotWithError:(NSError **)error; @end diff --git a/WebDriverAgentLib/Utilities/FBXCodeCompatibility.m b/WebDriverAgentLib/Utilities/FBXCodeCompatibility.m index b13a79e55..b78dff6d2 100644 --- a/WebDriverAgentLib/Utilities/FBXCodeCompatibility.m +++ b/WebDriverAgentLib/Utilities/FBXCodeCompatibility.m @@ -20,9 +20,9 @@ @implementation XCUIElementQuery (FBCompatibility) -- (XCElementSnapshot *)fb_uniqueSnapshotWithError:(NSError **)error +- (id)fb_uniqueSnapshotWithError:(NSError **)error { - return [self uniqueMatchingSnapshotWithError:error]; + return (id)[self uniqueMatchingSnapshotWithError:error]; } - (XCUIElement *)fb_firstMatch diff --git a/WebDriverAgentLib/Utilities/FBXPath.m b/WebDriverAgentLib/Utilities/FBXPath.m index eae3ee438..8a3cc2d60 100644 --- a/WebDriverAgentLib/Utilities/FBXPath.m +++ b/WebDriverAgentLib/Utilities/FBXPath.m @@ -368,15 +368,12 @@ + (int)writeXmlWithRootElement:(id)root NSArray> *children; if ([root isKindOfClass:XCUIElement.class]) { XCUIElement *element = (XCUIElement *)root; - NSMutableArray *snapshotAttributes = [NSMutableArray arrayWithArray:FBStandardAttributeNames()]; if (nil == includedAttributes || [includedAttributes containsObject:FBVisibleAttribute.class]) { - [snapshotAttributes addObject:FB_XCAXAIsVisibleAttributeName]; // If the app is not idle state while we retrieve the visiblity state // then the snapshot retrieval operation might freeze and time out [element.application fb_waitUntilStableWithTimeout:FBConfiguration.animationCoolOffTimeout]; } - currentSnapshot = [element fb_snapshotWithAttributes:snapshotAttributes.copy - maxDepth:nil]; + currentSnapshot = [element fb_takeSnapshot:YES]; children = currentSnapshot.children; } else { currentSnapshot = (id)root; diff --git a/WebDriverAgentLib/Utilities/XCTestPrivateSymbols.h b/WebDriverAgentLib/Utilities/XCTestPrivateSymbols.h index 87199ff35..da99cfd58 100644 --- a/WebDriverAgentLib/Utilities/XCTestPrivateSymbols.h +++ b/WebDriverAgentLib/Utilities/XCTestPrivateSymbols.h @@ -19,6 +19,9 @@ extern NSString *FB_XCAXAIsVisibleAttributeName; extern NSNumber *FB_XCAXAIsElementAttribute; extern NSString *FB_XCAXAIsElementAttributeName; +/*! Accessibility identifier for visible frame attribute */ +extern NSString *FB_XCAXAVisibleFrameAttributeName; + /*! Getter for XCTest logger */ extern id (*XCDebugLogger)(void); diff --git a/WebDriverAgentLib/Utilities/XCTestPrivateSymbols.m b/WebDriverAgentLib/Utilities/XCTestPrivateSymbols.m index 861a78660..502a6f8b7 100644 --- a/WebDriverAgentLib/Utilities/XCTestPrivateSymbols.m +++ b/WebDriverAgentLib/Utilities/XCTestPrivateSymbols.m @@ -18,6 +18,7 @@ NSString *FB_XCAXAIsVisibleAttributeName = @"XC_kAXXCAttributeIsVisible"; NSNumber *FB_XCAXAIsElementAttribute; NSString *FB_XCAXAIsElementAttributeName = @"XC_kAXXCAttributeIsElement"; +NSString *FB_XCAXAVisibleFrameAttributeName = @"XC_kAXXCAttributeVisibleFrame"; void (*XCSetDebugLogger)(id ); id (*XCDebugLogger)(void); diff --git a/WebDriverAgentTests/IntegrationTests/FBElementAttributeTests.m b/WebDriverAgentTests/IntegrationTests/FBElementAttributeTests.m index 2d6f30c5b..7c094b600 100644 --- a/WebDriverAgentTests/IntegrationTests/FBElementAttributeTests.m +++ b/WebDriverAgentTests/IntegrationTests/FBElementAttributeTests.m @@ -71,6 +71,7 @@ - (void)testButtonAttributes XCTAssertEqualObjects(element.wdLabel, @"Button"); XCTAssertNil(element.wdValue); XCTAssertFalse(element.wdSelected); + XCTAssertTrue(element.fb_isVisible); [element tap]; XCTAssertTrue(element.wdValue.boolValue); XCTAssertTrue(element.wdSelected); @@ -133,7 +134,7 @@ - (void)testSliderAttributes XCTAssertEqualObjects(element.wdType, @"XCUIElementTypeSlider"); XCTAssertNil(element.wdName); XCTAssertNil(element.wdLabel); - XCTAssertEqualObjects(element.wdValue, @"50%"); + XCTAssertTrue([element.wdValue containsString:@"50"]); } - (void)testActivityIndicatorAttributes diff --git a/WebDriverAgentTests/IntegrationTests/FBElementSwipingTests.m b/WebDriverAgentTests/IntegrationTests/FBElementSwipingTests.m index 0a9d2f5c4..ec5c853d0 100644 --- a/WebDriverAgentTests/IntegrationTests/FBElementSwipingTests.m +++ b/WebDriverAgentTests/IntegrationTests/FBElementSwipingTests.m @@ -72,7 +72,7 @@ - (void)testSwipeDownWithVelocity } [self.scrollView fb_swipeWithDirection:@"up" velocity:@2500]; FBAssertInvisibleCell(@"0"); - [self.scrollView fb_swipeWithDirection:@"down" velocity:@2500]; + [self.scrollView fb_swipeWithDirection:@"down" velocity:@3000]; FBAssertVisibleCell(@"0"); } diff --git a/WebDriverAgentTests/IntegrationTests/FBW3CTouchActionsIntegrationTests.m b/WebDriverAgentTests/IntegrationTests/FBW3CTouchActionsIntegrationTests.m index ccb996aa3..f7a3c7e02 100644 --- a/WebDriverAgentTests/IntegrationTests/FBW3CTouchActionsIntegrationTests.m +++ b/WebDriverAgentTests/IntegrationTests/FBW3CTouchActionsIntegrationTests.m @@ -424,7 +424,7 @@ - (void)verifyPickerWheelPositionChangeWithGesture:(NSArray)destinationSnapshot { XCUIElement *matchingElement = self.testedView.buttons.allElementsBoundByIndex.firstObject; - FBAssertWaitTillBecomesTrue(nil != matchingElement.fb_takeSnapshot); + FBAssertWaitTillBecomesTrue(nil != [matchingElement fb_takeSnapshot:YES]); - id snapshot = matchingElement.fb_takeSnapshot; + id snapshot = matchingElement.lastSnapshot; // Over iOS13, snapshot returns a child. // The purpose of here is return a single element to replace children with an empty array for testing. snapshot.children = @[]; diff --git a/WebDriverAgentTests/IntegrationTests/XCElementSnapshotHelperTests.m b/WebDriverAgentTests/IntegrationTests/XCElementSnapshotHelperTests.m index 418c7869d..55d8852a8 100644 --- a/WebDriverAgentTests/IntegrationTests/XCElementSnapshotHelperTests.m +++ b/WebDriverAgentTests/IntegrationTests/XCElementSnapshotHelperTests.m @@ -44,7 +44,8 @@ - (void)testDescendantsMatchingType @"Deadlock app", @"Touch", ]]; - NSArray> *matchingSnapshots = [[FBXCElementSnapshotWrapper ensureWrapped:self.testedView.fb_takeSnapshot] + NSArray> *matchingSnapshots = [[FBXCElementSnapshotWrapper ensureWrapped: + [self.testedView fb_takeSnapshot:YES]] fb_descendantsMatchingType:XCUIElementTypeButton]; XCTAssertEqual(matchingSnapshots.count, expectedLabels.count); NSArray *labels = [matchingSnapshots valueForKeyPath:@"@distinctUnionOfObjects.label"]; @@ -59,7 +60,8 @@ - (void)testParentMatchingType { XCUIElement *button = self.testedApplication.buttons[@"Alerts"]; FBAssertWaitTillBecomesTrue(button.exists); - id windowSnapshot = [[FBXCElementSnapshotWrapper ensureWrapped:button.fb_takeSnapshot] + id windowSnapshot = [[FBXCElementSnapshotWrapper ensureWrapped: + [self.testedView fb_takeSnapshot:YES]] fb_parentMatchingType:XCUIElementTypeWindow]; XCTAssertNotNil(windowSnapshot); XCTAssertEqual(windowSnapshot.elementType, XCUIElementTypeWindow); @@ -86,7 +88,8 @@ - (void)testParentMatchingOneOfTypes { XCUIElement *todayPickerWheel = self.testedApplication.pickerWheels[@"Today"]; FBAssertWaitTillBecomesTrue(todayPickerWheel.exists); - id datePicker = [[FBXCElementSnapshotWrapper ensureWrapped:todayPickerWheel.fb_takeSnapshot] + id datePicker = [[FBXCElementSnapshotWrapper ensureWrapped: + [todayPickerWheel fb_takeSnapshot:YES]] fb_parentMatchingOneOfTypes:@[@(XCUIElementTypeDatePicker), @(XCUIElementTypeWindow)]]; XCTAssertNotNil(datePicker); XCTAssertEqual(datePicker.elementType, XCUIElementTypeDatePicker); @@ -96,7 +99,8 @@ - (void)testParentMatchingOneOfTypesWithXCUIElementTypeAny { XCUIElement *todayPickerWheel = self.testedApplication.pickerWheels[@"Today"]; FBAssertWaitTillBecomesTrue(todayPickerWheel.exists); - id otherSnapshot =[[FBXCElementSnapshotWrapper ensureWrapped:todayPickerWheel.fb_takeSnapshot] + id otherSnapshot =[[FBXCElementSnapshotWrapper ensureWrapped: + [todayPickerWheel fb_takeSnapshot:YES]] fb_parentMatchingOneOfTypes:@[@(XCUIElementTypeAny)]]; XCTAssertNotNil(otherSnapshot); } @@ -105,7 +109,8 @@ - (void)testParentMatchingOneOfTypesWithAbsentParents { XCUIElement *todayPickerWheel = self.testedApplication.pickerWheels[@"Today"]; FBAssertWaitTillBecomesTrue(todayPickerWheel.exists); - id otherSnapshot = [[FBXCElementSnapshotWrapper ensureWrapped:todayPickerWheel.fb_takeSnapshot] + id otherSnapshot = [[FBXCElementSnapshotWrapper ensureWrapped: + [todayPickerWheel fb_takeSnapshot:YES]] fb_parentMatchingOneOfTypes:@[@(XCUIElementTypeTab), @(XCUIElementTypeLink)]]; XCTAssertNil(otherSnapshot); } @@ -136,8 +141,9 @@ - (void)testParentMatchingOneOfTypesWithFilter @(XCUIElementTypeCollectionView), @(XCUIElementTypeTable), ]; - id scrollView = [[FBXCElementSnapshotWrapper ensureWrapped:threeStaticText.fb_takeSnapshot] - fb_parentMatchingOneOfTypes:acceptedParents + id scrollView = [[FBXCElementSnapshotWrapper ensureWrapped: + [threeStaticText fb_takeSnapshot:YES]] + fb_parentMatchingOneOfTypes:acceptedParents filter:^BOOL(id snapshot) { return [[FBXCElementSnapshotWrapper ensureWrapped:snapshot] isWDVisible]; }]; @@ -153,7 +159,8 @@ - (void)testParentMatchingOneOfTypesWithFilterRetruningNo @(XCUIElementTypeCollectionView), @(XCUIElementTypeTable), ]; - id scrollView = [[FBXCElementSnapshotWrapper ensureWrapped:threeStaticText.fb_takeSnapshot] + id scrollView = [[FBXCElementSnapshotWrapper ensureWrapped: + [threeStaticText fb_takeSnapshot:YES]] fb_parentMatchingOneOfTypes:acceptedParents filter:^BOOL(id snapshot) { return NO; @@ -165,7 +172,9 @@ - (void)testDescendantsCellSnapshots { XCUIElement *scrollView = self.testedApplication.scrollViews[@"scrollView"]; FBAssertWaitTillBecomesTrue(self.testedApplication.staticTexts[@"3"].fb_isVisible); - NSArray *cells = [[FBXCElementSnapshotWrapper ensureWrapped:scrollView.fb_takeSnapshot] fb_descendantsCellSnapshots]; + NSArray *cells = [[FBXCElementSnapshotWrapper ensureWrapped: + [scrollView fb_takeSnapshot:YES]] + fb_descendantsCellSnapshots]; XCTAssertGreaterThanOrEqual(cells.count, 10); id element = cells.firstObject; XCTAssertEqualObjects(element.label, @"0"); @@ -192,7 +201,9 @@ - (void)testParentCellSnapshot { FBAssertWaitTillBecomesTrue(self.testedApplication.staticTexts[@"3"].fb_isVisible); XCUIElement *threeStaticText = self.testedApplication.staticTexts[@"3"]; - id xcuiElementCell = [[FBXCElementSnapshotWrapper ensureWrapped:threeStaticText.fb_takeSnapshot] fb_parentCellSnapshot]; + id xcuiElementCell = [[FBXCElementSnapshotWrapper ensureWrapped: + [threeStaticText fb_takeSnapshot:YES]] + fb_parentCellSnapshot]; XCTAssertEqual(xcuiElementCell.elementType, 75); } diff --git a/WebDriverAgentTests/IntegrationTests/XCElementSnapshotHitPointTests.m b/WebDriverAgentTests/IntegrationTests/XCElementSnapshotHitPointTests.m index 0acfe0f9c..b5635d6dc 100644 --- a/WebDriverAgentTests/IntegrationTests/XCElementSnapshotHitPointTests.m +++ b/WebDriverAgentTests/IntegrationTests/XCElementSnapshotHitPointTests.m @@ -23,7 +23,7 @@ - (void)testAccessibilityActivationPoint [self launchApplication]; [self goToAttributesPage]; XCUIElement *dstBtn = self.testedApplication.buttons[@"not_accessible"]; - CGPoint hitPoint = [FBXCElementSnapshotWrapper ensureWrapped:dstBtn.fb_takeSnapshot].fb_hitPoint.CGPointValue; + CGPoint hitPoint = [FBXCElementSnapshotWrapper ensureWrapped:[dstBtn fb_takeSnapshot:NO]].fb_hitPoint.CGPointValue; XCTAssertTrue(hitPoint.x > 0 && hitPoint.y > 0); } diff --git a/WebDriverAgentTests/IntegrationTests/XCUIElementHelperIntegrationTests.m b/WebDriverAgentTests/IntegrationTests/XCUIElementHelperIntegrationTests.m index 496bd353d..17396d106 100644 --- a/WebDriverAgentTests/IntegrationTests/XCUIElementHelperIntegrationTests.m +++ b/WebDriverAgentTests/IntegrationTests/XCUIElementHelperIntegrationTests.m @@ -41,9 +41,11 @@ - (void)testDescendantsFiltering [allElements addObjectsFromArray:windows]; NSMutableArray> *buttonSnapshots = [NSMutableArray array]; - [buttonSnapshots addObject:[buttons.firstObject fb_takeSnapshot]]; - - NSArray *result = [self.testedApplication fb_filterDescendantsWithSnapshots:buttonSnapshots selfUID:nil onlyChildren:NO]; + [buttonSnapshots addObject:[buttons.firstObject fb_takeSnapshot:YES]]; + + NSArray *result = [self.testedApplication fb_filterDescendantsWithSnapshots:buttonSnapshots + selfUID:nil + onlyChildren:NO]; XCTAssertEqual(1, result.count); XCTAssertEqual([result.firstObject elementType], XCUIElementTypeButton); } diff --git a/WebDriverAgentTests/UnitTests/Doubles/XCElementSnapshotDouble.m b/WebDriverAgentTests/UnitTests/Doubles/XCElementSnapshotDouble.m index d52c2904c..fc0814c1e 100644 --- a/WebDriverAgentTests/UnitTests/Doubles/XCElementSnapshotDouble.m +++ b/WebDriverAgentTests/UnitTests/Doubles/XCElementSnapshotDouble.m @@ -98,4 +98,14 @@ - (NSArray *)children return @[]; } +- (NSArray *)_allDescendants +{ + return @[]; +} + +- (CGRect)visibleFrame +{ + return CGRectZero; +} + @end diff --git a/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.h b/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.h index d40945545..5720ef8ab 100644 --- a/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.h +++ b/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.h @@ -19,7 +19,6 @@ @property (nonatomic, readwrite, nullable) id lastSnapshot; @property (nonatomic, assign) BOOL fb_isObstructedByAlert; @property (nonatomic, readonly, nonnull) NSString *fb_cacheId; -@property (nonatomic, nullable) NSNumber *fb_isResolvedFromCache; @property (nonatomic, readwrite, copy, nonnull) NSDictionary *wdRect; @property (nonatomic, readwrite, assign) CGRect wdFrame; @property (nonatomic, readwrite, copy, nonnull) NSString *wdUID; @@ -39,7 +38,7 @@ @property (nonatomic, readwrite, getter=isWDAccessibilityContainer) BOOL wdAccessibilityContainer; - (void)resolve; -- (id _Nonnull)fb_takeSnapshot; +- (id _Nonnull)fb_takeSnapshot:(BOOL)inDepth; - (nullable id)query; // Checks diff --git a/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.m b/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.m index e9792f132..9e65324b3 100644 --- a/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.m +++ b/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.m @@ -68,7 +68,7 @@ - (void)fb_nativeResolve self.didResolve = YES; } -- (id)fb_takeSnapshot +- (id _Nonnull)fb_takeSnapshot:(BOOL)inDepth; { return [self lastSnapshot]; } diff --git a/WebDriverAgentTests/UnitTests/FBElementCacheTests.m b/WebDriverAgentTests/UnitTests/FBElementCacheTests.m index e81a77300..79eed7ad0 100644 --- a/WebDriverAgentTests/UnitTests/FBElementCacheTests.m +++ b/WebDriverAgentTests/UnitTests/FBElementCacheTests.m @@ -43,10 +43,8 @@ - (void)testFetchingElement XCUIElement *element = (XCUIElement *)XCUIElementDouble.new; NSString *uuid = [self.cache storeElement:element]; XCTAssertNotNil(uuid, @"Stored index should be higher than 0"); - XCTAssertFalse(element.fb_isResolvedFromCache.boolValue); XCUIElement *cachedElement = [self.cache elementForUUID:uuid]; XCTAssertEqual(element, cachedElement); - XCTAssertTrue(element.fb_isResolvedFromCache.boolValue); } - (void)testFetchingBadIndex diff --git a/WebDriverAgentTests/UnitTests_tvOS/Doubles/XCUIElementDouble.h b/WebDriverAgentTests/UnitTests_tvOS/Doubles/XCUIElementDouble.h index cb43c334d..a57aec620 100644 --- a/WebDriverAgentTests/UnitTests_tvOS/Doubles/XCUIElementDouble.h +++ b/WebDriverAgentTests/UnitTests_tvOS/Doubles/XCUIElementDouble.h @@ -18,7 +18,6 @@ @property (nonatomic, readwrite, assign) CGRect frame; @property (nonatomic, readwrite, nullable) id lastSnapshot; @property (nonatomic, assign) BOOL fb_isObstructedByAlert; -@property (nonatomic, nullable) NSNumber *fb_isResolvedFromCache; @property (nonatomic, readwrite, copy, nonnull) NSDictionary *wdRect; @property (nonatomic, readwrite, assign) CGRect wdFrame; @property (nonatomic, readwrite, copy, nonnull) NSString *wdUID; From 43a9c654916295f33631487b094645597f887eb4 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 16 Jan 2025 16:47:45 +0000 Subject: [PATCH 031/219] chore(release): 9.0.0 [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [9.0.0](https://github.com/appium/WebDriverAgent/compare/v8.12.2...v9.0.0) (2025-01-16) ### ⚠ BREAKING CHANGES * snapshotTimeout and customSnapshotTimeout settings have been removed as a result of the custom snapshotting logic removal ### Features * Refactor snapshotting mechanism ([#970](https://github.com/appium/WebDriverAgent/issues/970)) ([08f1306](https://github.com/appium/WebDriverAgent/commit/08f13060119c710f53b34a98c95683287c0365a0)) --- CHANGELOG.md | 10 ++++++++++ WebDriverAgentLib/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fe42c710..bef7aba1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## [9.0.0](https://github.com/appium/WebDriverAgent/compare/v8.12.2...v9.0.0) (2025-01-16) + +### ⚠ BREAKING CHANGES + +* snapshotTimeout and customSnapshotTimeout settings have been removed as a result of the custom snapshotting logic removal + +### Features + +* Refactor snapshotting mechanism ([#970](https://github.com/appium/WebDriverAgent/issues/970)) ([08f1306](https://github.com/appium/WebDriverAgent/commit/08f13060119c710f53b34a98c95683287c0365a0)) + ## [8.12.2](https://github.com/appium/WebDriverAgent/compare/v8.12.1...v8.12.2) (2025-01-13) ### Miscellaneous Chores diff --git a/WebDriverAgentLib/Info.plist b/WebDriverAgentLib/Info.plist index f263b2ad8..f7eb6cbcf 100644 --- a/WebDriverAgentLib/Info.plist +++ b/WebDriverAgentLib/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 8.12.2 + 9.0.0 CFBundleSignature ???? CFBundleVersion - 8.12.2 + 9.0.0 NSPrincipalClass diff --git a/package.json b/package.json index 4134f04db..22852e428 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "appium-webdriveragent", - "version": "8.12.2", + "version": "9.0.0", "description": "Package bundling WebDriverAgent", "main": "./build/index.js", "types": "./build/index.d.ts", From d8ce5c8ffe5366605fd419c484dd95409a784519 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Thu, 16 Jan 2025 10:44:33 -0800 Subject: [PATCH 032/219] ci: use master for actions/upload-artifact (#972) --- .github/workflows/wda-package.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/wda-package.yml b/.github/workflows/wda-package.yml index 8a7d7a526..642e9949e 100644 --- a/.github/workflows/wda-package.yml +++ b/.github/workflows/wda-package.yml @@ -57,11 +57,11 @@ jobs: ZIP_PKG_NAME: "${{ env.ZIP_PKG_NAME_TVOS }}" - name: Upload the built generic app package for iOS - uses: actions/upload-artifact@v3.1.0 + uses: actions/upload-artifact@master with: path: "${{ env.ZIP_PKG_NAME_IOS }}" - name: Upload the built generic app package for tvOS - uses: actions/upload-artifact@v3.1.0 + uses: actions/upload-artifact@master with: path: "${{ env.ZIP_PKG_NAME_TVOS }}" @@ -90,6 +90,6 @@ jobs: ARCHS: ${{ matrix.arch }} ZIP_PKG_NAME: "WebDriverAgentRunner${{ matrix.target }}-Build-Sim-${{ matrix.arch }}.zip" - name: Upload the built generic app package for WebDriverAgentRunner${{ matrix.target }} with ${{ matrix.arch }} - uses: actions/upload-artifact@v3.1.0 + uses: actions/upload-artifact@master with: path: "WebDriverAgentRunner${{ matrix.target }}-Build-Sim-${{ matrix.arch }}.zip" From c13a22767dd4b4001fd380ad3c76e22aa3e3194d Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Thu, 16 Jan 2025 13:23:55 -0800 Subject: [PATCH 033/219] ci: set proper name for each artifact (#974) * ci: add merge artifact * Update wda-package.yml * Update wda-package.yml --- .github/workflows/wda-package.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/wda-package.yml b/.github/workflows/wda-package.yml index 642e9949e..b89bec31f 100644 --- a/.github/workflows/wda-package.yml +++ b/.github/workflows/wda-package.yml @@ -29,7 +29,9 @@ jobs: runs-on: ${{ needs.host_machine.outputs.host }} env: + PKG_NAME_IOS: "WebDriverAgentRunner-Runner" ZIP_PKG_NAME_IOS: "WebDriverAgentRunner-Runner.zip" + PKG_NAME_TVOS: "WebDriverAgentRunner_tvOS-Runner" ZIP_PKG_NAME_TVOS: "WebDriverAgentRunner_tvOS-Runner.zip" steps: @@ -59,10 +61,12 @@ jobs: - name: Upload the built generic app package for iOS uses: actions/upload-artifact@master with: + name: "${{ env.PKG_NAME_IOS }}" path: "${{ env.ZIP_PKG_NAME_IOS }}" - name: Upload the built generic app package for tvOS uses: actions/upload-artifact@master with: + name: "${{ env.PKG_NAME_TVOS }}" path: "${{ env.ZIP_PKG_NAME_TVOS }}" for_simulator_devices: @@ -92,4 +96,5 @@ jobs: - name: Upload the built generic app package for WebDriverAgentRunner${{ matrix.target }} with ${{ matrix.arch }} uses: actions/upload-artifact@master with: + name: "WebDriverAgentRunner${{ matrix.target }}-Build-Sim-${{ matrix.arch }}" path: "WebDriverAgentRunner${{ matrix.target }}-Build-Sim-${{ matrix.arch }}.zip" From f2c752db4707b3864efb62b95b64abb487d28e4b Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Fri, 17 Jan 2025 09:06:01 +0100 Subject: [PATCH 034/219] chore: Optimize stable instance retrieval (#973) --- .../Categories/XCUIElement+FBFind.m | 1 - .../Categories/XCUIElement+FBPickerWheel.m | 3 ++- .../Categories/XCUIElement+FBResolve.h | 3 ++- .../Categories/XCUIElement+FBResolve.m | 22 +++++++---------- .../Categories/XCUIElement+FBUtilities.h | 3 --- .../Categories/XCUIElement+FBUtilities.m | 11 ++++----- .../Commands/FBElementCommands.m | 5 +++- .../Commands/FBFindElementCommands.m | 1 - WebDriverAgentLib/Routing/FBResponsePayload.m | 24 ++++++++++++++----- .../FBXPathIntegrationTests.m | 4 +--- .../IntegrationTests/XCUIElementFBFindTests.m | 6 ++++- .../XCUIElementHelperIntegrationTests.m | 1 - 12 files changed, 45 insertions(+), 39 deletions(-) diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBFind.m b/WebDriverAgentLib/Categories/XCUIElement+FBFind.m index e799be557..aa58afb51 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBFind.m +++ b/WebDriverAgentLib/Categories/XCUIElement+FBFind.m @@ -110,7 +110,6 @@ @implementation XCUIElement (FBFind) matchingSnapshots = @[snapshot]; } return [self fb_filterDescendantsWithSnapshots:matchingSnapshots - selfUID:self.fb_uid onlyChildren:NO]; } diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBPickerWheel.m b/WebDriverAgentLib/Categories/XCUIElement+FBPickerWheel.m index 881081fa1..975ab2afa 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBPickerWheel.m +++ b/WebDriverAgentLib/Categories/XCUIElement+FBPickerWheel.m @@ -12,6 +12,7 @@ #import "FBRunLoopSpinner.h" #import "FBXCElementSnapshot.h" #import "FBXCodeCompatibility.h" +#import "XCUIElement+FBUID.h" #import "XCUICoordinate.h" #import "XCUIElement+FBCaching.h" #import "XCUIElement+FBResolve.h" @@ -33,7 +34,7 @@ - (BOOL)fb_scrollWithOffset:(CGFloat)relativeHeightOffset error:(NSError **)erro // Fetching stable instance of an element allows it to be bounded to the // unique element identifier (UID), so it could be found next time even if its // id is different from the initial one. See https://github.com/appium/appium/issues/17569 - XCUIElement *stableInstance = self.fb_stableInstance; + XCUIElement *stableInstance = [self fb_stableInstanceWithUid:[FBXCElementSnapshotWrapper wdUIDWithSnapshot:snapshot]]; [endCoord tap]; return [[[[FBRunLoopSpinner new] timeout:VALUE_CHANGE_TIMEOUT] diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBResolve.h b/WebDriverAgentLib/Categories/XCUIElement+FBResolve.h index 80b218b06..f430e0b49 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBResolve.h +++ b/WebDriverAgentLib/Categories/XCUIElement+FBResolve.h @@ -27,10 +27,11 @@ NS_ASSUME_NONNULL_BEGIN Although, if the cached element instance is the one returned by this API call then the same element is going to be matched and no staleness exception will be thrown. + @param uid Element UUID @return Either the same element instance if `fb_isResolvedNatively` was set to NO (usually the cache for elements matched by xpath locators) or the stable instance of the self element based on the query by element's UUID. */ -- (XCUIElement *)fb_stableInstance; +- (XCUIElement *)fb_stableInstanceWithUid:(NSString *)uid; @end diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBResolve.m b/WebDriverAgentLib/Categories/XCUIElement+FBResolve.m index f52c72bf6..66511bf7f 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBResolve.m +++ b/WebDriverAgentLib/Categories/XCUIElement+FBResolve.m @@ -32,23 +32,19 @@ - (NSNumber *)fb_isResolvedNatively return nil == result ? @YES : result; } -- (XCUIElement *)fb_stableInstance +- (XCUIElement *)fb_stableInstanceWithUid:(NSString *)uid { - if (![self.fb_isResolvedNatively boolValue]) { + if (nil == uid || ![self.fb_isResolvedNatively boolValue] || [self isKindOfClass:XCUIApplication.class]) { return self; } - - XCUIElementQuery *query = [self isKindOfClass:XCUIApplication.class] - ? self.application.fb_query - : [self.application.fb_query descendantsMatchingType:XCUIElementTypeAny]; - NSString *uid = nil == self.fb_cachedSnapshot - ? self.fb_uid - : [FBXCElementSnapshotWrapper wdUIDWithSnapshot:(id)self.fb_cachedSnapshot]; - if (nil == uid) { - return self; + NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K = %@", FBStringify(FBXCElementSnapshotWrapper, fb_uid), uid]; + XCUIElementQuery *query = [self.application.fb_query descendantsMatchingType:XCUIElementTypeAny]; + XCUIElement *result = [query matchingPredicate:predicate].allElementsBoundByIndex.firstObject; + if (nil != result) { + result.fb_isResolvedNatively = @NO; + return result; } - NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K = %@",FBStringify(FBXCElementSnapshotWrapper, fb_uid), uid]; - return [query matchingPredicate:predicate].allElementsBoundByIndex.firstObject ?: self; + return self; } @end diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.h b/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.h index a16e581f4..83a369da1 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.h +++ b/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.h @@ -41,14 +41,11 @@ NS_ASSUME_NONNULL_BEGIN Filters elements by matching them to snapshots from the corresponding array @param snapshots Array of snapshots to be matched with - @param selfUID Optionally the unique identifier of the current element. - Providing it as an argument improves the performance of the method. @param onlyChildren Whether to only look for direct element children @return Array of filtered elements, which have matches in snapshots array */ - (NSArray *)fb_filterDescendantsWithSnapshots:(NSArray> *)snapshots - selfUID:(nullable NSString *)selfUID onlyChildren:(BOOL)onlyChildren; /** diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m b/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m index 7b6d52c03..9234ba8e3 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m +++ b/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m @@ -71,7 +71,6 @@ @implementation XCUIElement (FBUtilities) } - (NSArray *)fb_filterDescendantsWithSnapshots:(NSArray> *)snapshots - selfUID:(NSString *)selfUID onlyChildren:(BOOL)onlyChildren { if (0 == snapshots.count) { @@ -85,13 +84,11 @@ @implementation XCUIElement (FBUtilities) } } NSMutableArray *matchedElements = [NSMutableArray array]; - NSString *uid = selfUID; - if (nil == uid) { - uid = self.fb_uid; - } + NSString *uid = nil == self.lastSnapshot + ? self.fb_uid + : [FBXCElementSnapshotWrapper wdUIDWithSnapshot:self.lastSnapshot]; if (nil != uid && [matchedIds containsObject:uid]) { - XCUIElement *stableSelf = self.fb_stableInstance; - stableSelf.fb_isResolvedNatively = @NO; + XCUIElement *stableSelf = [self fb_stableInstanceWithUid:uid]; if (1 == snapshots.count) { return @[stableSelf]; } diff --git a/WebDriverAgentLib/Commands/FBElementCommands.m b/WebDriverAgentLib/Commands/FBElementCommands.m index 79fa30b8d..a03fbea41 100644 --- a/WebDriverAgentLib/Commands/FBElementCommands.m +++ b/WebDriverAgentLib/Commands/FBElementCommands.m @@ -35,6 +35,7 @@ #import "XCUIElement+FBWebDriverAttributes.h" #import "XCUIElement+FBTVFocuse.h" #import "XCUIElement+FBResolve.h" +#import "XCUIElement+FBUID.h" #import "FBElementTypeTransformer.h" #import "XCUIElement.h" #import "XCUIElementQuery.h" @@ -264,7 +265,9 @@ + (NSArray *)routes if (focusedElement != nil) { FBElementCache *elementCache = request.session.elementCache; BOOL useNativeCachingStrategy = request.session.useNativeCachingStrategy; - NSString *focusedUUID = [elementCache storeElement:(useNativeCachingStrategy ? focusedElement : focusedElement.fb_stableInstance)]; + NSString *focusedUUID = [elementCache storeElement:(useNativeCachingStrategy + ? focusedElement + : [focusedElement fb_stableInstanceWithUid:focusedElement.fb_uid])]; if (focusedUUID && [focusedUUID isEqualToString:(id)request.parameters[@"uuid"]]) { isFocused = YES; } diff --git a/WebDriverAgentLib/Commands/FBFindElementCommands.m b/WebDriverAgentLib/Commands/FBFindElementCommands.m index a92c5082e..0128d8ff7 100644 --- a/WebDriverAgentLib/Commands/FBFindElementCommands.m +++ b/WebDriverAgentLib/Commands/FBFindElementCommands.m @@ -87,7 +87,6 @@ + (NSArray *)routes && [FBXCElementSnapshotWrapper ensureWrapped:shot].wdVisible; }]; NSArray *cells = [element fb_filterDescendantsWithSnapshots:visibleCellSnapshots - selfUID:[FBXCElementSnapshotWrapper wdUIDWithSnapshot:snapshot] onlyChildren:NO]; return FBResponseWithCachedElements(cells, request.session.elementCache, FBConfiguration.shouldUseCompactResponses); } diff --git a/WebDriverAgentLib/Routing/FBResponsePayload.m b/WebDriverAgentLib/Routing/FBResponsePayload.m index dcaa77403..d6a73472b 100644 --- a/WebDriverAgentLib/Routing/FBResponsePayload.m +++ b/WebDriverAgentLib/Routing/FBResponsePayload.m @@ -34,23 +34,35 @@ return FBResponseWithStatus([FBCommandStatus okWithValue:object]); } -id FBResponseWithCachedElement(XCUIElement *element, FBElementCache *elementCache, BOOL compact) +XCUIElement *maybeStable(XCUIElement *element) { BOOL useNativeCachingStrategy = nil == FBSession.activeSession ? YES : FBSession.activeSession.useNativeCachingStrategy; - [elementCache storeElement:(useNativeCachingStrategy ? element : element.fb_stableInstance)]; + if (useNativeCachingStrategy) { + return element; + } + + XCUIElement *result = element; + id snapshot = element.lastSnapshot ?: [element fb_cachedSnapshot] ?: [element fb_takeSnapshot:NO]; + NSString *uid = [FBXCElementSnapshotWrapper wdUIDWithSnapshot:snapshot]; + if (nil != uid) { + result = [element fb_stableInstanceWithUid:uid]; + } + return result; +} + +id FBResponseWithCachedElement(XCUIElement *element, FBElementCache *elementCache, BOOL compact) +{ + [elementCache storeElement:maybeStable(element)]; return FBResponseWithStatus([FBCommandStatus okWithValue:FBDictionaryResponseWithElement(element, compact)]); } id FBResponseWithCachedElements(NSArray *elements, FBElementCache *elementCache, BOOL compact) { NSMutableArray *elementsResponse = [NSMutableArray array]; - BOOL useNativeCachingStrategy = nil == FBSession.activeSession - ? YES - : FBSession.activeSession.useNativeCachingStrategy; for (XCUIElement *element in elements) { - [elementCache storeElement:(useNativeCachingStrategy ? element : element.fb_stableInstance)]; + [elementCache storeElement:maybeStable(element)]; [elementsResponse addObject:FBDictionaryResponseWithElement(element, compact)]; } return FBResponseWithStatus([FBCommandStatus okWithValue:elementsResponse]); diff --git a/WebDriverAgentTests/IntegrationTests/FBXPathIntegrationTests.m b/WebDriverAgentTests/IntegrationTests/FBXPathIntegrationTests.m index a3b81c459..461a2ae94 100644 --- a/WebDriverAgentTests/IntegrationTests/FBXPathIntegrationTests.m +++ b/WebDriverAgentTests/IntegrationTests/FBXPathIntegrationTests.m @@ -43,9 +43,7 @@ - (void)setUp - (id)destinationSnapshot { XCUIElement *matchingElement = self.testedView.buttons.allElementsBoundByIndex.firstObject; - FBAssertWaitTillBecomesTrue(nil != [matchingElement fb_takeSnapshot:YES]); - - id snapshot = matchingElement.lastSnapshot; + id snapshot = [matchingElement fb_takeSnapshot:YES]; // Over iOS13, snapshot returns a child. // The purpose of here is return a single element to replace children with an empty array for testing. snapshot.children = @[]; diff --git a/WebDriverAgentTests/IntegrationTests/XCUIElementFBFindTests.m b/WebDriverAgentTests/IntegrationTests/XCUIElementFBFindTests.m index 713aee760..fb2b47e6d 100644 --- a/WebDriverAgentTests/IntegrationTests/XCUIElementFBFindTests.m +++ b/WebDriverAgentTests/IntegrationTests/XCUIElementFBFindTests.m @@ -15,6 +15,7 @@ #import "FBTestMacros.h" #import "XCUIElement.h" #import "XCUIElement+FBFind.h" +#import "XCUIElement+FBUID.h" #import "FBXCElementSnapshotWrapper+Helpers.h" #import "XCUIElement+FBIsVisible.h" #import "XCUIElement+FBClassChain.h" @@ -93,7 +94,10 @@ - (void)testStableInstance NSArray *matchingSnapshots = [self.testedView fb_descendantsMatchingIdentifier:@"Alerts" shouldReturnAfterFirstMatch:YES]; XCTAssertEqual(matchingSnapshots.count, 1); - for (XCUIElement *el in @[matchingSnapshots.lastObject, matchingSnapshots.lastObject.fb_stableInstance]) { + for (XCUIElement *el in @[ + matchingSnapshots.lastObject, + [matchingSnapshots.lastObject fb_stableInstanceWithUid:[matchingSnapshots.lastObject fb_uid]] + ]) { XCTAssertEqual(el.elementType, XCUIElementTypeButton); XCTAssertEqualObjects(el.label, @"Alerts"); } diff --git a/WebDriverAgentTests/IntegrationTests/XCUIElementHelperIntegrationTests.m b/WebDriverAgentTests/IntegrationTests/XCUIElementHelperIntegrationTests.m index 17396d106..f04f9e158 100644 --- a/WebDriverAgentTests/IntegrationTests/XCUIElementHelperIntegrationTests.m +++ b/WebDriverAgentTests/IntegrationTests/XCUIElementHelperIntegrationTests.m @@ -44,7 +44,6 @@ - (void)testDescendantsFiltering [buttonSnapshots addObject:[buttons.firstObject fb_takeSnapshot:YES]]; NSArray *result = [self.testedApplication fb_filterDescendantsWithSnapshots:buttonSnapshots - selfUID:nil onlyChildren:NO]; XCTAssertEqual(1, result.count); XCTAssertEqual([result.firstObject elementType], XCUIElementTypeButton); From c296efabe83bf9b2fcd1650c06b363344c5535e0 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 17 Jan 2025 08:08:50 +0000 Subject: [PATCH 035/219] chore(release): 9.0.1 [skip ci] ## [9.0.1](https://github.com/appium/WebDriverAgent/compare/v9.0.0...v9.0.1) (2025-01-17) ### Miscellaneous Chores * Optimize stable instance retrieval ([#973](https://github.com/appium/WebDriverAgent/issues/973)) ([f2c752d](https://github.com/appium/WebDriverAgent/commit/f2c752db4707b3864efb62b95b64abb487d28e4b)) --- CHANGELOG.md | 6 ++++++ WebDriverAgentLib/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bef7aba1f..66fb81d12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [9.0.1](https://github.com/appium/WebDriverAgent/compare/v9.0.0...v9.0.1) (2025-01-17) + +### Miscellaneous Chores + +* Optimize stable instance retrieval ([#973](https://github.com/appium/WebDriverAgent/issues/973)) ([f2c752d](https://github.com/appium/WebDriverAgent/commit/f2c752db4707b3864efb62b95b64abb487d28e4b)) + ## [9.0.0](https://github.com/appium/WebDriverAgent/compare/v8.12.2...v9.0.0) (2025-01-16) ### ⚠ BREAKING CHANGES diff --git a/WebDriverAgentLib/Info.plist b/WebDriverAgentLib/Info.plist index f7eb6cbcf..2d7429431 100644 --- a/WebDriverAgentLib/Info.plist +++ b/WebDriverAgentLib/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 9.0.0 + 9.0.1 CFBundleSignature ???? CFBundleVersion - 9.0.0 + 9.0.1 NSPrincipalClass diff --git a/package.json b/package.json index 22852e428..185998d38 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "appium-webdriveragent", - "version": "9.0.0", + "version": "9.0.1", "description": "Package bundling WebDriverAgent", "main": "./build/index.js", "types": "./build/index.d.ts", From ea3863a67d5cfa8bc2e48a1dc2c59052acd47937 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgars=20Egl=C4=ABtis?= <37242620+eglitise@users.noreply.github.com> Date: Mon, 3 Feb 2025 15:05:17 +0200 Subject: [PATCH 036/219] fix: update docs link in xcodebuild error message (#978) --- lib/xcodebuild.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/xcodebuild.js b/lib/xcodebuild.js index 54add615e..041d24ebe 100644 --- a/lib/xcodebuild.js +++ b/lib/xcodebuild.js @@ -36,6 +36,8 @@ const IGNORED_ERRORS_PATTERN = new RegExp( const RUNNER_SCHEME_TV = 'WebDriverAgentRunner_tvOS'; const LIB_SCHEME_TV = 'WebDriverAgentLib_tvOS'; +const REAL_DEVICES_CONFIG_DOCS_LINK = 'https://appium.github.io/appium-xcuitest-driver/latest/preparation/real-device-config/'; + const xcodeLog = logger.getLogger('Xcode'); @@ -378,8 +380,7 @@ export class XcodeBuild { ` order to check the Appium server log for build-related error messages.`; } else if (this.realDevice) { errorMessage += ` Consider checking the WebDriverAgent configuration guide` + - ` for real iOS devices at` + - ` https://github.com/appium/appium-xcuitest-driver/blob/master/docs/real-device-config.md.`; + ` for real iOS devices at ${REAL_DEVICES_CONFIG_DOCS_LINK}.`; } return reject(new Error(errorMessage)); } From a49a4858e351b109f92f97d226c5872fe9d2d543 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 3 Feb 2025 13:08:29 +0000 Subject: [PATCH 037/219] chore(release): 9.0.2 [skip ci] ## [9.0.2](https://github.com/appium/WebDriverAgent/compare/v9.0.1...v9.0.2) (2025-02-03) ### Bug Fixes * update docs link in xcodebuild error message ([#978](https://github.com/appium/WebDriverAgent/issues/978)) ([ea3863a](https://github.com/appium/WebDriverAgent/commit/ea3863a67d5cfa8bc2e48a1dc2c59052acd47937)) --- CHANGELOG.md | 6 ++++++ WebDriverAgentLib/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66fb81d12..5af870074 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [9.0.2](https://github.com/appium/WebDriverAgent/compare/v9.0.1...v9.0.2) (2025-02-03) + +### Bug Fixes + +* update docs link in xcodebuild error message ([#978](https://github.com/appium/WebDriverAgent/issues/978)) ([ea3863a](https://github.com/appium/WebDriverAgent/commit/ea3863a67d5cfa8bc2e48a1dc2c59052acd47937)) + ## [9.0.1](https://github.com/appium/WebDriverAgent/compare/v9.0.0...v9.0.1) (2025-01-17) ### Miscellaneous Chores diff --git a/WebDriverAgentLib/Info.plist b/WebDriverAgentLib/Info.plist index 2d7429431..e8593d550 100644 --- a/WebDriverAgentLib/Info.plist +++ b/WebDriverAgentLib/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 9.0.1 + 9.0.2 CFBundleSignature ???? CFBundleVersion - 9.0.1 + 9.0.2 NSPrincipalClass diff --git a/package.json b/package.json index 185998d38..9fcbb31d2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "appium-webdriveragent", - "version": "9.0.1", + "version": "9.0.2", "description": "Package bundling WebDriverAgent", "main": "./build/index.js", "types": "./build/index.d.ts", From 34b303c4e226d6a75a45a14eee7ca5e253e67737 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Wed, 5 Feb 2025 12:39:38 -0800 Subject: [PATCH 038/219] fix: add nullable signature (#979) --- WebDriverAgentLib/Categories/XCUIElement+FBResolve.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBResolve.h b/WebDriverAgentLib/Categories/XCUIElement+FBResolve.h index f430e0b49..e59ddd89f 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBResolve.h +++ b/WebDriverAgentLib/Categories/XCUIElement+FBResolve.h @@ -31,7 +31,7 @@ NS_ASSUME_NONNULL_BEGIN @return Either the same element instance if `fb_isResolvedNatively` was set to NO (usually the cache for elements matched by xpath locators) or the stable instance of the self element based on the query by element's UUID. */ -- (XCUIElement *)fb_stableInstanceWithUid:(NSString *)uid; +- (XCUIElement *)fb_stableInstanceWithUid:(NSString *__nullable)uid; @end From 1a0402b76d85ab43cda736fcbce723382ece8079 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 5 Feb 2025 20:42:58 +0000 Subject: [PATCH 039/219] chore(release): 9.0.3 [skip ci] ## [9.0.3](https://github.com/appium/WebDriverAgent/compare/v9.0.2...v9.0.3) (2025-02-05) ### Bug Fixes * add nullable signature ([#979](https://github.com/appium/WebDriverAgent/issues/979)) ([34b303c](https://github.com/appium/WebDriverAgent/commit/34b303c4e226d6a75a45a14eee7ca5e253e67737)) --- CHANGELOG.md | 6 ++++++ WebDriverAgentLib/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5af870074..cc77dfa3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [9.0.3](https://github.com/appium/WebDriverAgent/compare/v9.0.2...v9.0.3) (2025-02-05) + +### Bug Fixes + +* add nullable signature ([#979](https://github.com/appium/WebDriverAgent/issues/979)) ([34b303c](https://github.com/appium/WebDriverAgent/commit/34b303c4e226d6a75a45a14eee7ca5e253e67737)) + ## [9.0.2](https://github.com/appium/WebDriverAgent/compare/v9.0.1...v9.0.2) (2025-02-03) ### Bug Fixes diff --git a/WebDriverAgentLib/Info.plist b/WebDriverAgentLib/Info.plist index e8593d550..85644c02f 100644 --- a/WebDriverAgentLib/Info.plist +++ b/WebDriverAgentLib/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 9.0.2 + 9.0.3 CFBundleSignature ???? CFBundleVersion - 9.0.2 + 9.0.3 NSPrincipalClass diff --git a/package.json b/package.json index 9fcbb31d2..cf3a4f8ae 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "appium-webdriveragent", - "version": "9.0.2", + "version": "9.0.3", "description": "Package bundling WebDriverAgent", "main": "./build/index.js", "types": "./build/index.d.ts", From 19efbdd69ff9edff20c0c318bd39c29963d4d51d Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Fri, 21 Feb 2025 08:35:42 +0100 Subject: [PATCH 040/219] fix: Accept reqBasePath proxy option (#982) --- lib/webdriveragent.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/webdriveragent.js b/lib/webdriveragent.js index e47b9c752..a2a9dbb0d 100644 --- a/lib/webdriveragent.js +++ b/lib/webdriveragent.js @@ -585,6 +585,9 @@ export class WebDriverAgent { timeout: this.wdaConnectionTimeout, keepAlive: true, }; + if (this.args.reqBasePath) { + proxyOpts.reqBasePath = this.args.reqBasePath; + } this.jwproxy = new JWProxy(proxyOpts); this.jwproxy.sessionId = sessionId; From d99087404008f586483427bf29d7607dee58ebfc Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 21 Feb 2025 07:38:25 +0000 Subject: [PATCH 041/219] chore(release): 9.0.4 [skip ci] ## [9.0.4](https://github.com/appium/WebDriverAgent/compare/v9.0.3...v9.0.4) (2025-02-21) ### Bug Fixes * Accept reqBasePath proxy option ([#982](https://github.com/appium/WebDriverAgent/issues/982)) ([19efbdd](https://github.com/appium/WebDriverAgent/commit/19efbdd69ff9edff20c0c318bd39c29963d4d51d)) --- CHANGELOG.md | 6 ++++++ WebDriverAgentLib/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc77dfa3d..33ad8c0a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [9.0.4](https://github.com/appium/WebDriverAgent/compare/v9.0.3...v9.0.4) (2025-02-21) + +### Bug Fixes + +* Accept reqBasePath proxy option ([#982](https://github.com/appium/WebDriverAgent/issues/982)) ([19efbdd](https://github.com/appium/WebDriverAgent/commit/19efbdd69ff9edff20c0c318bd39c29963d4d51d)) + ## [9.0.3](https://github.com/appium/WebDriverAgent/compare/v9.0.2...v9.0.3) (2025-02-05) ### Bug Fixes diff --git a/WebDriverAgentLib/Info.plist b/WebDriverAgentLib/Info.plist index 85644c02f..e218b456c 100644 --- a/WebDriverAgentLib/Info.plist +++ b/WebDriverAgentLib/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 9.0.3 + 9.0.4 CFBundleSignature ???? CFBundleVersion - 9.0.3 + 9.0.4 NSPrincipalClass diff --git a/package.json b/package.json index cf3a4f8ae..1d7711f37 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "appium-webdriveragent", - "version": "9.0.3", + "version": "9.0.4", "description": "Package bundling WebDriverAgent", "main": "./build/index.js", "types": "./build/index.d.ts", From f92f1cde0fe914086103a110844bbe3bc0e3c4a6 Mon Sep 17 00:00:00 2001 From: Abhinav Pandey Date: Thu, 27 Feb 2025 00:47:18 +0530 Subject: [PATCH 042/219] fix: add autorelease pool to drain temporary objects (#983) --- .../Categories/XCUIApplication+FBHelpers.m | 60 ++++++++++-------- .../Categories/XCUIElement+FBFind.m | 4 +- .../Categories/XCUIElement+FBIsVisible.m | 10 ++- .../Categories/XCUIElement+FBResolve.m | 12 ++-- .../Categories/XCUIElement+FBScrolling.m | 32 +++++----- .../Categories/XCUIElement+FBUtilities.m | 40 ++++++------ WebDriverAgentLib/Routing/FBResponsePayload.m | 61 ++++++++++--------- WebDriverAgentLib/Utilities/FBXPath.m | 32 +++++----- .../Utilities/NSPredicate+FBFormat.m | 6 +- 9 files changed, 145 insertions(+), 112 deletions(-) diff --git a/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m b/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m index 03d4407f2..ac3d07ce9 100644 --- a/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m +++ b/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m @@ -238,9 +238,11 @@ + (NSDictionary *)dictionaryForElement:(id)snapshot if ([childElements count]) { info[@"children"] = [[NSMutableArray alloc] init]; for (id childSnapshot in childElements) { - [info[@"children"] addObject:[self dictionaryForElement:childSnapshot - recursive:YES - excludedAttributes:excludedAttributes]]; + @autoreleasepool { + [info[@"children"] addObject:[self dictionaryForElement:childSnapshot + recursive:YES + excludedAttributes:excludedAttributes]]; + } } } return info; @@ -262,9 +264,11 @@ + (NSDictionary *)accessibilityInfoForElement:(id)snapshot } else { NSMutableArray *children = [[NSMutableArray alloc] init]; for (id childSnapshot in snapshot.children) { - NSDictionary *childInfo = [self accessibilityInfoForElement:childSnapshot]; - if ([childInfo count]) { - [children addObject: childInfo]; + @autoreleasepool { + NSDictionary *childInfo = [self accessibilityInfoForElement:childSnapshot]; + if ([childInfo count]) { + [children addObject: childInfo]; + } } } if ([children count]) { @@ -420,31 +424,33 @@ - (BOOL)fb_dismissKeyboardWithKeyNames:(nullable NSArray *)keyNames [invocation setSelector:selector]; [invocation setArgument:&auditTypes atIndex:2]; BOOL (^issueHandler)(id) = ^BOOL(id issue) { - NSString *auditType = @""; - NSDictionary *valuesToNamesMap = auditTypeValuesToNames(); - NSNumber *auditTypeValue = [issue valueForKey:@"auditType"]; - if (nil != auditTypeValue) { - auditType = valuesToNamesMap[auditTypeValue] ?: [auditTypeValue stringValue]; - } - - id extractedElement = extractIssueProperty(issue, @"element"); - - id elementSnapshot = [extractedElement fb_cachedSnapshot] ?: [extractedElement fb_takeSnapshot:NO]; - NSDictionary *elementAttributes = elementSnapshot + @autoreleasepool { + NSString *auditType = @""; + NSDictionary *valuesToNamesMap = auditTypeValuesToNames(); + NSNumber *auditTypeValue = [issue valueForKey:@"auditType"]; + if (nil != auditTypeValue) { + auditType = valuesToNamesMap[auditTypeValue] ?: [auditTypeValue stringValue]; + } + + id extractedElement = extractIssueProperty(issue, @"element"); + + id elementSnapshot = [extractedElement fb_cachedSnapshot] ?: [extractedElement fb_takeSnapshot:NO]; + NSDictionary *elementAttributes = elementSnapshot ? [self.class dictionaryForElement:elementSnapshot recursive:NO excludedAttributes:customAttributesToExclude] : @{}; - - [resultArray addObject:@{ - @"detailedDescription": extractIssueProperty(issue, @"detailedDescription") ?: @"", - @"compactDescription": extractIssueProperty(issue, @"compactDescription") ?: @"", - @"auditType": auditType, - @"element": [extractedElement description] ?: @"", - @"elementDescription": [extractedElement debugDescription] ?: @"", - @"elementAttributes": elementAttributes ?: @{}, - }]; - return YES; + + [resultArray addObject:@{ + @"detailedDescription": extractIssueProperty(issue, @"detailedDescription") ?: @"", + @"compactDescription": extractIssueProperty(issue, @"compactDescription") ?: @"", + @"auditType": auditType, + @"element": [extractedElement description] ?: @"", + @"elementDescription": [extractedElement debugDescription] ?: @"", + @"elementAttributes": elementAttributes ?: @{}, + }]; + return YES; + } }; [invocation setArgument:&issueHandler atIndex:3]; [invocation setArgument:&error atIndex:4]; diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBFind.m b/WebDriverAgentLib/Categories/XCUIElement+FBFind.m index aa58afb51..d33fce1ea 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBFind.m +++ b/WebDriverAgentLib/Categories/XCUIElement+FBFind.m @@ -121,7 +121,9 @@ @implementation XCUIElement (FBFind) { NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id snapshot, NSDictionary * _Nullable bindings) { - return [[FBXCElementSnapshotWrapper wdNameWithSnapshot:snapshot] isEqualToString:accessibilityId]; + @autoreleasepool { + return [[FBXCElementSnapshotWrapper wdNameWithSnapshot:snapshot] isEqualToString:accessibilityId]; + } }]; return [self fb_descendantsMatchingPredicate:predicate shouldReturnAfterFirstMatch:shouldReturnAfterFirstMatch]; diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBIsVisible.m b/WebDriverAgentLib/Categories/XCUIElement+FBIsVisible.m index 80ee1bd9b..aa1f7c28d 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBIsVisible.m +++ b/WebDriverAgentLib/Categories/XCUIElement+FBIsVisible.m @@ -25,8 +25,10 @@ @implementation XCUIElement (FBIsVisible) - (BOOL)fb_isVisible { - id snapshot = [self fb_takeSnapshot:NO]; - return [FBXCElementSnapshotWrapper ensureWrapped:snapshot].fb_isVisible; + @autoreleasepool { + id snapshot = [self fb_takeSnapshot:NO]; + return [FBXCElementSnapshotWrapper ensureWrapped:snapshot].fb_isVisible; + } } @end @@ -64,7 +66,9 @@ - (BOOL)fb_isVisible NSMutableDictionary *updatedValue = [NSMutableDictionary dictionaryWithDictionary:self.additionalAttributes ?: @{}]; [updatedValue setObject:attributeValue forKey:FB_XCAXAIsVisibleAttribute]; self.snapshot.additionalAttributes = updatedValue.copy; - return [attributeValue boolValue]; + @autoreleasepool { + return [attributeValue boolValue]; + } } NSLog(@"Cannot determine visiblity of %@ natively: %@. Defaulting to: %@", diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBResolve.m b/WebDriverAgentLib/Categories/XCUIElement+FBResolve.m index 66511bf7f..43882b077 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBResolve.m +++ b/WebDriverAgentLib/Categories/XCUIElement+FBResolve.m @@ -38,11 +38,13 @@ - (XCUIElement *)fb_stableInstanceWithUid:(NSString *)uid return self; } NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K = %@", FBStringify(FBXCElementSnapshotWrapper, fb_uid), uid]; - XCUIElementQuery *query = [self.application.fb_query descendantsMatchingType:XCUIElementTypeAny]; - XCUIElement *result = [query matchingPredicate:predicate].allElementsBoundByIndex.firstObject; - if (nil != result) { - result.fb_isResolvedNatively = @NO; - return result; + @autoreleasepool { + XCUIElementQuery *query = [self.application.fb_query descendantsMatchingType:XCUIElementTypeAny]; + XCUIElement *result = [query matchingPredicate:predicate].allElementsBoundByIndex.firstObject; + if (nil != result) { + result.fb_isResolvedNatively = @NO; + return result; + } } return self; } diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBScrolling.m b/WebDriverAgentLib/Categories/XCUIElement+FBScrolling.m index 4ebd14b32..23177131a 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBScrolling.m +++ b/WebDriverAgentLib/Categories/XCUIElement+FBScrolling.m @@ -178,23 +178,25 @@ - (BOOL)fb_scrollToVisibleWithNormalizedScrollDistance:(CGFloat)normalizedScroll FBXCElementSnapshotWrapper *scrollViewWrapped = [FBXCElementSnapshotWrapper ensureWrapped:scrollView]; // Scrolling till cell is visible and get current value of frames while (![self fb_isEquivalentElementSnapshotVisible:prescrollSnapshot] && scrollCount < maxScrollCount) { - if (targetCellIndex < visibleCellIndex) { - scrollDirection == FBXCUIElementScrollDirectionVertical ? - [scrollViewWrapped fb_scrollUpByNormalizedDistance:normalizedScrollDistance - inApplication:self.application] : - [scrollViewWrapped fb_scrollLeftByNormalizedDistance:normalizedScrollDistance - inApplication:self.application]; - } - else { - scrollDirection == FBXCUIElementScrollDirectionVertical ? - [scrollViewWrapped fb_scrollDownByNormalizedDistance:normalizedScrollDistance + @autoreleasepool { + if (targetCellIndex < visibleCellIndex) { + scrollDirection == FBXCUIElementScrollDirectionVertical ? + [scrollViewWrapped fb_scrollUpByNormalizedDistance:normalizedScrollDistance inApplication:self.application] : - [scrollViewWrapped fb_scrollRightByNormalizedDistance:normalizedScrollDistance - inApplication:self.application]; + [scrollViewWrapped fb_scrollLeftByNormalizedDistance:normalizedScrollDistance + inApplication:self.application]; + } + else { + scrollDirection == FBXCUIElementScrollDirectionVertical ? + [scrollViewWrapped fb_scrollDownByNormalizedDistance:normalizedScrollDistance + inApplication:self.application] : + [scrollViewWrapped fb_scrollRightByNormalizedDistance:normalizedScrollDistance + inApplication:self.application]; + } + scrollCount++; + // Wait for scroll animation + [self fb_waitUntilStableWithTimeout:FBConfiguration.animationCoolOffTimeout]; } - scrollCount++; - // Wait for scroll animation - [self fb_waitUntilStableWithTimeout:FBConfiguration.animationCoolOffTimeout]; } if (scrollCount >= maxScrollCount) { diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m b/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m index 9234ba8e3..26e274c18 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m +++ b/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m @@ -46,22 +46,26 @@ @implementation XCUIElement (FBUtilities) - (id)fb_takeSnapshot:(BOOL)inDepth { - NSError *error = nil; - self.lastSnapshot = inDepth - ? [self.fb_query fb_uniqueSnapshotWithError:&error] - : (id)[self snapshotWithError:&error]; - if (nil == self.lastSnapshot) { - NSString *hintText = @"Make sure the application UI has the expected state"; - if (nil != error && [error.localizedDescription containsString:@"Identity Binding"]) { - hintText = [NSString stringWithFormat:@"%@. You could also try to switch the binding strategy using the 'boundElementsByIndex' setting for the element lookup", hintText]; + __block id snapshot = nil; + @autoreleasepool { + NSError *error = nil; + snapshot = inDepth + ? [self.fb_query fb_uniqueSnapshotWithError:&error] + : (id)[self snapshotWithError:&error]; + if (nil == snapshot) { + NSString *hintText = @"Make sure the application UI has the expected state"; + if (nil != error && [error.localizedDescription containsString:@"Identity Binding"]) { + hintText = [NSString stringWithFormat:@"%@. You could also try to switch the binding strategy using the 'boundElementsByIndex' setting for the element lookup", hintText]; + } + NSString *reason = [NSString stringWithFormat:@"The previously found element \"%@\" is not present in the current view anymore. %@", + self.description, hintText]; + if (nil != error) { + reason = [NSString stringWithFormat:@"%@. Original error: %@", reason, error.localizedDescription]; + } + @throw [NSException exceptionWithName:FBStaleElementException reason:reason userInfo:@{}]; } - NSString *reason = [NSString stringWithFormat:@"The previously found element \"%@\" is not present in the current view anymore. %@", - self.description, hintText]; - if (nil != error) { - reason = [NSString stringWithFormat:@"%@. Original error: %@", reason, error.localizedDescription]; - } - @throw [NSException exceptionWithName:FBStaleElementException reason:reason userInfo:@{}]; } + self.lastSnapshot = snapshot; return self.lastSnapshot; } @@ -78,9 +82,11 @@ @implementation XCUIElement (FBUtilities) } NSMutableArray *matchedIds = [NSMutableArray new]; for (id snapshot in snapshots) { - NSString *uid = [FBXCElementSnapshotWrapper wdUIDWithSnapshot:snapshot]; - if (nil != uid) { - [matchedIds addObject:uid]; + @autoreleasepool { + NSString *uid = [FBXCElementSnapshotWrapper wdUIDWithSnapshot:snapshot]; + if (nil != uid) { + [matchedIds addObject:uid]; + } } } NSMutableArray *matchedElements = [NSMutableArray array]; diff --git a/WebDriverAgentLib/Routing/FBResponsePayload.m b/WebDriverAgentLib/Routing/FBResponsePayload.m index d6a73472b..f17517633 100644 --- a/WebDriverAgentLib/Routing/FBResponsePayload.m +++ b/WebDriverAgentLib/Routing/FBResponsePayload.m @@ -103,35 +103,40 @@ inline NSDictionary *FBDictionaryResponseWithElement(XCUIElement *element, BOOL compact) { - id snapshot = element.lastSnapshot ?: element.fb_cachedSnapshot ?: [element fb_takeSnapshot:YES]; - NSDictionary *compactResult = FBToElementDict((NSString *)[FBXCElementSnapshotWrapper wdUIDWithSnapshot:snapshot]); - if (compact) { - return compactResult; - } + __block NSDictionary *elementResponse = nil; + @autoreleasepool { + id snapshot = element.lastSnapshot ?: element.fb_cachedSnapshot ?: [element fb_takeSnapshot:YES]; + NSDictionary *compactResult = FBToElementDict((NSString *)[FBXCElementSnapshotWrapper wdUIDWithSnapshot:snapshot]); + if (compact) { + elementResponse = compactResult; + return elementResponse; + } - NSMutableDictionary *result = compactResult.mutableCopy; - FBXCElementSnapshotWrapper *wrappedSnapshot = [FBXCElementSnapshotWrapper ensureWrapped:snapshot]; - NSArray *fields = [FBConfiguration.elementResponseAttributes componentsSeparatedByString:@","]; - for (NSString *field in fields) { - // 'name' here is the w3c-approved identifier for what we mean by 'type' - if ([field isEqualToString:@"name"] || [field isEqualToString:@"type"]) { - result[field] = wrappedSnapshot.wdType; - } else if ([field isEqualToString:@"text"]) { - result[field] = FBFirstNonEmptyValue(wrappedSnapshot.wdValue, wrappedSnapshot.wdLabel) ?: [NSNull null]; - } else if ([field isEqualToString:@"rect"]) { - result[field] = wrappedSnapshot.wdRect; - } else if ([field isEqualToString:@"enabled"]) { - result[field] = @(wrappedSnapshot.wdEnabled); - } else if ([field isEqualToString:@"displayed"]) { - result[field] = @(wrappedSnapshot.wdVisible); - } else if ([field isEqualToString:@"selected"]) { - result[field] = @(wrappedSnapshot.wdSelected); - } else if ([field isEqualToString:@"label"]) { - result[field] = wrappedSnapshot.wdLabel ?: [NSNull null]; - } else if ([field hasPrefix:arbitraryAttrPrefix]) { - NSString *attributeName = [field substringFromIndex:[arbitraryAttrPrefix length]]; - result[field] = [wrappedSnapshot fb_valueForWDAttributeName:attributeName] ?: [NSNull null]; + NSMutableDictionary *result = compactResult.mutableCopy; + FBXCElementSnapshotWrapper *wrappedSnapshot = [FBXCElementSnapshotWrapper ensureWrapped:snapshot]; + NSArray *fields = [FBConfiguration.elementResponseAttributes componentsSeparatedByString:@","]; + for (NSString *field in fields) { + // 'name' here is the w3c-approved identifier for what we mean by 'type' + if ([field isEqualToString:@"name"] || [field isEqualToString:@"type"]) { + result[field] = wrappedSnapshot.wdType; + } else if ([field isEqualToString:@"text"]) { + result[field] = FBFirstNonEmptyValue(wrappedSnapshot.wdValue, wrappedSnapshot.wdLabel) ?: [NSNull null]; + } else if ([field isEqualToString:@"rect"]) { + result[field] = wrappedSnapshot.wdRect; + } else if ([field isEqualToString:@"enabled"]) { + result[field] = @(wrappedSnapshot.wdEnabled); + } else if ([field isEqualToString:@"displayed"]) { + result[field] = @(wrappedSnapshot.wdVisible); + } else if ([field isEqualToString:@"selected"]) { + result[field] = @(wrappedSnapshot.wdSelected); + } else if ([field isEqualToString:@"label"]) { + result[field] = wrappedSnapshot.wdLabel ?: [NSNull null]; + } else if ([field hasPrefix:arbitraryAttrPrefix]) { + NSString *attributeName = [field substringFromIndex:[arbitraryAttrPrefix length]]; + result[field] = [wrappedSnapshot fb_valueForWDAttributeName:attributeName] ?: [NSNull null]; + } } + elementResponse = result.copy; } - return result.copy; + return elementResponse; } diff --git a/WebDriverAgentLib/Utilities/FBXPath.m b/WebDriverAgentLib/Utilities/FBXPath.m index 8a3cc2d60..6276cfae6 100644 --- a/WebDriverAgentLib/Utilities/FBXPath.m +++ b/WebDriverAgentLib/Utilities/FBXPath.m @@ -364,7 +364,7 @@ + (int)writeXmlWithRootElement:(id)root { NSAssert((indexPath == nil && elementStore == nil) || (indexPath != nil && elementStore != nil), @"Either both or none of indexPath and elementStore arguments should be equal to nil", nil); - id currentSnapshot; + __block id currentSnapshot; NSArray> *children; if ([root isKindOfClass:XCUIElement.class]) { XCUIElement *element = (XCUIElement *)root; @@ -373,7 +373,9 @@ + (int)writeXmlWithRootElement:(id)root // then the snapshot retrieval operation might freeze and time out [element.application fb_waitUntilStableWithTimeout:FBConfiguration.animationCoolOffTimeout]; } - currentSnapshot = [element fb_takeSnapshot:YES]; + @autoreleasepool { + currentSnapshot = [element fb_takeSnapshot:YES]; + } children = currentSnapshot.children; } else { currentSnapshot = (id)root; @@ -400,18 +402,20 @@ + (int)writeXmlWithRootElement:(id)root } for (NSUInteger i = 0; i < [children count]; i++) { - id childSnapshot = [children objectAtIndex:i]; - NSString *newIndexPath = (indexPath != nil) ? [indexPath stringByAppendingFormat:@",%lu", (unsigned long)i] : nil; - if (elementStore != nil && newIndexPath != nil) { - [elementStore setObject:childSnapshot forKey:(id)newIndexPath]; - } - rc = [self writeXmlWithRootElement:[FBXCElementSnapshotWrapper ensureWrapped:childSnapshot] - indexPath:newIndexPath - elementStore:elementStore - includedAttributes:includedAttributes - writer:writer]; - if (rc < 0) { - return rc; + @autoreleasepool { + id childSnapshot = [children objectAtIndex:i]; + NSString *newIndexPath = (indexPath != nil) ? [indexPath stringByAppendingFormat:@",%lu", (unsigned long)i] : nil; + if (elementStore != nil && newIndexPath != nil) { + [elementStore setObject:childSnapshot forKey:(id)newIndexPath]; + } + rc = [self writeXmlWithRootElement:[FBXCElementSnapshotWrapper ensureWrapped:childSnapshot] + indexPath:newIndexPath + elementStore:elementStore + includedAttributes:includedAttributes + writer:writer]; + if (rc < 0) { + return rc; + } } } diff --git a/WebDriverAgentLib/Utilities/NSPredicate+FBFormat.m b/WebDriverAgentLib/Utilities/NSPredicate+FBFormat.m index 8a033e707..2b20fcaa5 100644 --- a/WebDriverAgentLib/Utilities/NSPredicate+FBFormat.m +++ b/WebDriverAgentLib/Utilities/NSPredicate+FBFormat.m @@ -59,8 +59,10 @@ + (instancetype)fb_snapshotBlockPredicateWithPredicate:(NSPredicate *)input NSPredicate *wdPredicate = [self.class fb_formatSearchPredicate:input]; return [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary * _Nullable bindings) { - FBXCElementSnapshotWrapper *wrappedSnapshot = [FBXCElementSnapshotWrapper ensureWrapped:evaluatedObject]; - return [wdPredicate evaluateWithObject:wrappedSnapshot]; + @autoreleasepool { + FBXCElementSnapshotWrapper *wrappedSnapshot = [FBXCElementSnapshotWrapper ensureWrapped:evaluatedObject]; + return [wdPredicate evaluateWithObject:wrappedSnapshot]; + } }]; } From 4f0dfee950626d5a105ad73a914a3146ddb0f8ca Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 26 Feb 2025 19:20:03 +0000 Subject: [PATCH 043/219] chore(release): 9.0.5 [skip ci] ## [9.0.5](https://github.com/appium/WebDriverAgent/compare/v9.0.4...v9.0.5) (2025-02-26) ### Bug Fixes * add autorelease pool to drain temporary objects ([#983](https://github.com/appium/WebDriverAgent/issues/983)) ([f92f1cd](https://github.com/appium/WebDriverAgent/commit/f92f1cde0fe914086103a110844bbe3bc0e3c4a6)) --- CHANGELOG.md | 6 ++++++ WebDriverAgentLib/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33ad8c0a5..632761867 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [9.0.5](https://github.com/appium/WebDriverAgent/compare/v9.0.4...v9.0.5) (2025-02-26) + +### Bug Fixes + +* add autorelease pool to drain temporary objects ([#983](https://github.com/appium/WebDriverAgent/issues/983)) ([f92f1cd](https://github.com/appium/WebDriverAgent/commit/f92f1cde0fe914086103a110844bbe3bc0e3c4a6)) + ## [9.0.4](https://github.com/appium/WebDriverAgent/compare/v9.0.3...v9.0.4) (2025-02-21) ### Bug Fixes diff --git a/WebDriverAgentLib/Info.plist b/WebDriverAgentLib/Info.plist index e218b456c..746b99d25 100644 --- a/WebDriverAgentLib/Info.plist +++ b/WebDriverAgentLib/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 9.0.4 + 9.0.5 CFBundleSignature ???? CFBundleVersion - 9.0.4 + 9.0.5 NSPrincipalClass diff --git a/package.json b/package.json index 1d7711f37..34c9e9db5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "appium-webdriveragent", - "version": "9.0.4", + "version": "9.0.5", "description": "Package bundling WebDriverAgent", "main": "./build/index.js", "types": "./build/index.d.ts", From 46dc417da9f4a843838b414c0b154d6f478dbc0b Mon Sep 17 00:00:00 2001 From: Abhinav Pandey Date: Fri, 28 Feb 2025 20:32:28 +0530 Subject: [PATCH 044/219] fix: optimize LRU cache (#985) --- WebDriverAgentLib/Routing/FBElementCache.m | 12 +++++++- .../Utilities/LRUCache/LRUCache.h | 7 +++++ .../Utilities/LRUCache/LRUCache.m | 8 +++++ .../UnitTests/FBLRUCacheTests.m | 29 +++++++++++++++++++ 4 files changed, 55 insertions(+), 1 deletion(-) diff --git a/WebDriverAgentLib/Routing/FBElementCache.m b/WebDriverAgentLib/Routing/FBElementCache.m index 3228f752c..b87ec8cf5 100644 --- a/WebDriverAgentLib/Routing/FBElementCache.m +++ b/WebDriverAgentLib/Routing/FBElementCache.m @@ -73,7 +73,17 @@ - (XCUIElement *)elementForUUID:(NSString *)uuid checkStaleness:(BOOL)checkStale @throw [NSException exceptionWithName:FBStaleElementException reason:reason userInfo:@{}]; } if (checkStaleness) { - [element fb_takeSnapshot:NO]; + @try { + [element fb_takeSnapshot:NO]; + } @catch (NSException *exception) { + // if the snapshot method threw FBStaleElementException (implying the element is stale) we need to explicitly remove it from the cache, PR: https://github.com/appium/WebDriverAgent/pull/985 + if ([exception.name isEqualToString:FBStaleElementException]) { + @synchronized (self.elementCache) { + [self.elementCache removeObjectForKey:uuid]; + } + } + @throw exception; + } } return element; } diff --git a/WebDriverAgentLib/Utilities/LRUCache/LRUCache.h b/WebDriverAgentLib/Utilities/LRUCache/LRUCache.h index 70614235f..dbfb4cfbc 100644 --- a/WebDriverAgentLib/Utilities/LRUCache/LRUCache.h +++ b/WebDriverAgentLib/Utilities/LRUCache/LRUCache.h @@ -54,6 +54,13 @@ NS_ASSUME_NONNULL_BEGIN */ - (NSArray *)allObjects; +/** + Removes the object associated with the specified key from the cache. + + @param key The key identifying the object to remove. + */ +- (void)removeObjectForKey:(id)key; + @end NS_ASSUME_NONNULL_END diff --git a/WebDriverAgentLib/Utilities/LRUCache/LRUCache.m b/WebDriverAgentLib/Utilities/LRUCache/LRUCache.m index 4f3a9ad0d..731d74404 100644 --- a/WebDriverAgentLib/Utilities/LRUCache/LRUCache.m +++ b/WebDriverAgentLib/Utilities/LRUCache/LRUCache.m @@ -135,4 +135,12 @@ - (void)alignSize } } +- (void)removeObjectForKey:(id)key +{ + LRUCacheNode *node = self.store[key]; + if (node != nil) { + [self removeNode:node]; + } +} + @end diff --git a/WebDriverAgentTests/UnitTests/FBLRUCacheTests.m b/WebDriverAgentTests/UnitTests/FBLRUCacheTests.m index 6d8438734..6f788a253 100644 --- a/WebDriverAgentTests/UnitTests/FBLRUCacheTests.m +++ b/WebDriverAgentTests/UnitTests/FBLRUCacheTests.m @@ -96,4 +96,33 @@ - (void)testInsertionLoop XCTAssertEqualObjects(@[@(count)], cache.allObjects); } +- (void)testRemoveExistingObjectForKey { + LRUCache *cache = [[LRUCache alloc] initWithCapacity:3]; + [cache setObject:@"foo" forKey:@"bar"]; + [cache setObject:@"foo2" forKey:@"bar2"]; + [cache setObject:@"foo3" forKey:@"bar3"]; + [self assertArray:@[@"foo3", @"foo2", @"foo"] equalsTo:cache.allObjects]; + [cache removeObjectForKey:@"bar2"]; + XCTAssertNil([cache objectForKey:@"bar2"]); + [self assertArray:@[@"foo3", @"foo"] equalsTo:cache.allObjects]; +} + +- (void)testRemoveNonExistingObjectForKey { + LRUCache *cache = [[LRUCache alloc] initWithCapacity:2]; + [cache setObject:@"foo" forKey:@"bar"]; + [cache removeObjectForKey:@"nonExisting"]; + XCTAssertNotNil([cache objectForKey:@"bar"]); + [self assertArray:@[@"foo"] equalsTo:cache.allObjects]; +} + +- (void)testRemoveAndInsertFlow { + LRUCache *cache = [[LRUCache alloc] initWithCapacity:2]; + [cache setObject:@"foo" forKey:@"bar"]; + [cache setObject:@"foo2" forKey:@"bar2"]; + [cache removeObjectForKey:@"bar"]; + XCTAssertNil([cache objectForKey:@"bar"]); + [cache setObject:@"foo3" forKey:@"bar3"]; + [self assertArray:@[@"foo3", @"foo2"] equalsTo:cache.allObjects]; +} + @end From d7cff1a389586f3f492cfd789175e21d838f21da Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 28 Feb 2025 15:06:27 +0000 Subject: [PATCH 045/219] chore(release): 9.0.6 [skip ci] ## [9.0.6](https://github.com/appium/WebDriverAgent/compare/v9.0.5...v9.0.6) (2025-02-28) ### Bug Fixes * optimize LRU cache ([#985](https://github.com/appium/WebDriverAgent/issues/985)) ([46dc417](https://github.com/appium/WebDriverAgent/commit/46dc417da9f4a843838b414c0b154d6f478dbc0b)) --- CHANGELOG.md | 6 ++++++ WebDriverAgentLib/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 632761867..169152856 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [9.0.6](https://github.com/appium/WebDriverAgent/compare/v9.0.5...v9.0.6) (2025-02-28) + +### Bug Fixes + +* optimize LRU cache ([#985](https://github.com/appium/WebDriverAgent/issues/985)) ([46dc417](https://github.com/appium/WebDriverAgent/commit/46dc417da9f4a843838b414c0b154d6f478dbc0b)) + ## [9.0.5](https://github.com/appium/WebDriverAgent/compare/v9.0.4...v9.0.5) (2025-02-26) ### Bug Fixes diff --git a/WebDriverAgentLib/Info.plist b/WebDriverAgentLib/Info.plist index 746b99d25..39be9a6fe 100644 --- a/WebDriverAgentLib/Info.plist +++ b/WebDriverAgentLib/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 9.0.5 + 9.0.6 CFBundleSignature ???? CFBundleVersion - 9.0.5 + 9.0.6 NSPrincipalClass diff --git a/package.json b/package.json index 34c9e9db5..95f0b1b33 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "appium-webdriveragent", - "version": "9.0.5", + "version": "9.0.6", "description": "Package bundling WebDriverAgent", "main": "./build/index.js", "types": "./build/index.d.ts", From 8c3a1cb30655ed8d1a77d25bbeca71ee48c2ec3e Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Sun, 9 Mar 2025 00:37:45 -0800 Subject: [PATCH 046/219] feat: add placeholderValue (#987) * initial implementation * add tests * update tests * update test --- .../XCUIElement+FBWebDriverAttributes.m | 9 +++++++++ WebDriverAgentLib/Routing/FBElement.h | 3 +++ WebDriverAgentLib/Utilities/FBXPath.m | 20 +++++++++++++++++++ .../FBElementAttributeTests.m | 1 + .../FBXPathIntegrationTests.m | 6 +++--- .../Doubles/XCElementSnapshotDouble.m | 2 +- .../UnitTests/Doubles/XCUIElementDouble.h | 1 + .../UnitTests/Doubles/XCUIElementDouble.m | 1 + WebDriverAgentTests/UnitTests/FBXPathTests.m | 12 +++++------ 9 files changed, 45 insertions(+), 10 deletions(-) diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBWebDriverAttributes.m b/WebDriverAgentLib/Categories/XCUIElement+FBWebDriverAttributes.m index f99158c7f..4efe2dde6 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBWebDriverAttributes.m +++ b/WebDriverAgentLib/Categories/XCUIElement+FBWebDriverAttributes.m @@ -115,6 +115,15 @@ - (NSString *)wdLabel return FBTransferEmptyStringToNil(label); } +- (NSString *)wdPlaceholderValue +{ + NSString *placehlderValue = self.placeholderValue; + if (nil != placehlderValue) { + return placehlderValue; + } + return FBTransferEmptyStringToNil(placehlderValue); +} + - (NSString *)wdType { return [FBElementTypeTransformer stringWithElementType:self.elementType]; diff --git a/WebDriverAgentLib/Routing/FBElement.h b/WebDriverAgentLib/Routing/FBElement.h index 7cc8f269c..0b3b8b098 100644 --- a/WebDriverAgentLib/Routing/FBElement.h +++ b/WebDriverAgentLib/Routing/FBElement.h @@ -62,6 +62,9 @@ NS_ASSUME_NONNULL_BEGIN /*! Element's index relatively to its parent. Starts from zero */ @property (nonatomic, readonly) NSUInteger wdIndex; +/*! Element's placeholder value */ +@property (nonatomic, readonly, copy, nullable) NSString *wdPlaceholderValue; + /** Returns value of given property specified in WebDriver Spec Check the FBElement protocol to get list of supported attributes. diff --git a/WebDriverAgentLib/Utilities/FBXPath.m b/WebDriverAgentLib/Utilities/FBXPath.m index 6276cfae6..d36291fdd 100644 --- a/WebDriverAgentLib/Utilities/FBXPath.m +++ b/WebDriverAgentLib/Utilities/FBXPath.m @@ -100,6 +100,10 @@ + (int)recordWithWriter:(xmlTextWriterPtr)writer forValue:(NSString *)value; @end +@interface FBPlaceholderValueAttribute : FBElementAttribute + +@end + #if TARGET_OS_TV @interface FBFocusedAttribute : FBElementAttribute @@ -491,6 +495,7 @@ + (int)recordWithWriter:(xmlTextWriterPtr)writer forElement:(id)eleme FBHeightAttribute.class, FBIndexAttribute.class, FBHittableAttribute.class, + FBPlaceholderValueAttribute.class, ]; } @@ -713,3 +718,18 @@ + (int)recordWithWriter:(xmlTextWriterPtr)writer forValue:(NSString *)value return rc; } @end + + +@implementation FBPlaceholderValueAttribute + ++ (NSString *)name +{ + return @"placeholderValue"; +} + ++ (NSString *)valueForElement:(id)element +{ + return element.wdPlaceholderValue; +} + +@end diff --git a/WebDriverAgentTests/IntegrationTests/FBElementAttributeTests.m b/WebDriverAgentTests/IntegrationTests/FBElementAttributeTests.m index 7c094b600..15cf628ab 100644 --- a/WebDriverAgentTests/IntegrationTests/FBElementAttributeTests.m +++ b/WebDriverAgentTests/IntegrationTests/FBElementAttributeTests.m @@ -154,6 +154,7 @@ - (void)testSwitchAttributes XCTAssertEqualObjects(element.wdType, @"XCUIElementTypeSwitch"); XCTAssertNil(element.wdName); XCTAssertNil(element.wdLabel); + XCTAssertNil(element.wdPlaceholderValue); XCTAssertEqualObjects(element.wdValue, @"1"); XCTAssertFalse(element.wdSelected); XCTAssertTrue(element.wdHittable); diff --git a/WebDriverAgentTests/IntegrationTests/FBXPathIntegrationTests.m b/WebDriverAgentTests/IntegrationTests/FBXPathIntegrationTests.m index 461a2ae94..adbadeb32 100644 --- a/WebDriverAgentTests/IntegrationTests/FBXPathIntegrationTests.m +++ b/WebDriverAgentTests/IntegrationTests/FBXPathIntegrationTests.m @@ -57,7 +57,7 @@ - (void)testSingleDescendantXMLRepresentation NSString *xmlStr = [FBXPath xmlStringWithRootElement:wrappedSnapshot options:nil]; XCTAssertNotNil(xmlStr); - NSString *expectedXml = [NSString stringWithFormat:@"\n<%@ type=\"%@\" name=\"%@\" label=\"%@\" enabled=\"%@\" visible=\"%@\" accessible=\"%@\" x=\"%@\" y=\"%@\" width=\"%@\" height=\"%@\" index=\"%lu\"/>\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]; + NSString *expectedXml = [NSString stringWithFormat:@"\n<%@ type=\"%@\" name=\"%@\" label=\"%@\" enabled=\"%@\" visible=\"%@\" accessible=\"%@\" x=\"%@\" y=\"%@\" width=\"%@\" height=\"%@\" index=\"%lu\" placeholderValue=\"%@\"/>\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.wdPlaceholderValue]; XCTAssertEqualObjects(xmlStr, expectedXml); } @@ -70,7 +70,7 @@ - (void)testSingleDescendantXMLRepresentationWithScope NSString *xmlStr = [FBXPath xmlStringWithRootElement:wrappedSnapshot options:options]; XCTAssertNotNil(xmlStr); - NSString *expectedXml = [NSString stringWithFormat:@"\n<%@>\n <%@ type=\"%@\" name=\"%@\" label=\"%@\" enabled=\"%@\" visible=\"%@\" accessible=\"%@\" x=\"%@\" y=\"%@\" width=\"%@\" height=\"%@\" index=\"%lu\"/>\n\n", scope, 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, scope]; + NSString *expectedXml = [NSString stringWithFormat:@"\n<%@>\n <%@ type=\"%@\" name=\"%@\" label=\"%@\" enabled=\"%@\" visible=\"%@\" accessible=\"%@\" x=\"%@\" y=\"%@\" width=\"%@\" height=\"%@\" index=\"%lu\" placeholderValue=\"%@\"/>\n\n", scope, 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.wdPlaceholderValue, scope]; XCTAssertEqualObjects(xmlStr, expectedXml); } @@ -83,7 +83,7 @@ - (void)testSingleDescendantXMLRepresentationWithoutAttributes NSString *xmlStr = [FBXPath xmlStringWithRootElement:wrappedSnapshot options:options]; XCTAssertNotNil(xmlStr); - NSString *expectedXml = [NSString stringWithFormat:@"\n<%@ type=\"%@\" name=\"%@\" label=\"%@\" accessible=\"%@\" x=\"%@\" y=\"%@\" width=\"%@\" height=\"%@\"/>\n", wrappedSnapshot.wdType, wrappedSnapshot.wdType, wrappedSnapshot.wdName, wrappedSnapshot.wdLabel, FBBoolToString(wrappedSnapshot.wdAccessible), [wrappedSnapshot.wdRect[@"x"] stringValue], [wrappedSnapshot.wdRect[@"y"] stringValue], [wrappedSnapshot.wdRect[@"width"] stringValue], [wrappedSnapshot.wdRect[@"height"] stringValue]]; + NSString *expectedXml = [NSString stringWithFormat:@"\n<%@ type=\"%@\" name=\"%@\" label=\"%@\" accessible=\"%@\" x=\"%@\" y=\"%@\" width=\"%@\" height=\"%@\" placeholderValue=\"%@\"/>\n", wrappedSnapshot.wdType, wrappedSnapshot.wdType, wrappedSnapshot.wdName, wrappedSnapshot.wdLabel, FBBoolToString(wrappedSnapshot.wdAccessible), [wrappedSnapshot.wdRect[@"x"] stringValue], [wrappedSnapshot.wdRect[@"y"] stringValue], [wrappedSnapshot.wdRect[@"width"] stringValue], [wrappedSnapshot.wdRect[@"height"] stringValue], wrappedSnapshot.wdPlaceholderValue]; XCTAssertEqualObjects(xmlStr, expectedXml); } diff --git a/WebDriverAgentTests/UnitTests/Doubles/XCElementSnapshotDouble.m b/WebDriverAgentTests/UnitTests/Doubles/XCElementSnapshotDouble.m index fc0814c1e..e9e1a2a76 100644 --- a/WebDriverAgentTests/UnitTests/Doubles/XCElementSnapshotDouble.m +++ b/WebDriverAgentTests/UnitTests/Doubles/XCElementSnapshotDouble.m @@ -60,7 +60,7 @@ - (XCUIUserInterfaceSizeClass)verticalSizeClass - (NSString *)placeholderValue { - return @""; + return @"testPlaceholderValue"; } - (BOOL)isSelected diff --git a/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.h b/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.h index 5720ef8ab..b2269874f 100644 --- a/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.h +++ b/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.h @@ -33,6 +33,7 @@ @property (nonatomic, readwrite, getter=isWDAccessible) BOOL wdAccessible; @property (nonatomic, readwrite, getter = isWDFocused) BOOL wdFocused; @property (nonatomic, readwrite, getter = isWDHittable) BOOL wdHittable; +@property (nonatomic, copy, readwrite, nullable) NSString *wdPlaceholderValue; @property (copy, nonnull) NSArray *children; @property (nonatomic, readwrite, assign) XCUIElementType elementType; @property (nonatomic, readwrite, getter=isWDAccessibilityContainer) BOOL wdAccessibilityContainer; diff --git a/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.m b/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.m index 9e65324b3..5f731d7ba 100644 --- a/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.m +++ b/WebDriverAgentTests/UnitTests/Doubles/XCUIElementDouble.m @@ -23,6 +23,7 @@ - (id)init self.wdName = @"testName"; self.wdLabel = @"testLabel"; self.wdValue = @"magicValue"; + self.wdPlaceholderValue = @"testPlaceholderValue"; self.wdVisible = YES; self.wdAccessible = YES; self.wdEnabled = YES; diff --git a/WebDriverAgentTests/UnitTests/FBXPathTests.m b/WebDriverAgentTests/UnitTests/FBXPathTests.m index ce9171107..ad0d1988f 100644 --- a/WebDriverAgentTests/UnitTests/FBXPathTests.m +++ b/WebDriverAgentTests/UnitTests/FBXPathTests.m @@ -63,8 +63,8 @@ - (void)testDefaultXPathPresentation NSString *resultXml = [self xmlStringWithElement:element xpathQuery:nil excludingAttributes:nil]; - NSString *expectedXml = [NSString stringWithFormat:@"\n<%@ type=\"%@\" value=\"%@\" name=\"%@\" label=\"%@\" enabled=\"%@\" visible=\"%@\" accessible=\"%@\" x=\"%@\" y=\"%@\" width=\"%@\" height=\"%@\" index=\"%lu\" private_indexPath=\"top\"/>\n", - element.wdType, element.wdType, element.wdValue, element.wdName, element.wdLabel, FBBoolToString(element.wdEnabled), FBBoolToString(element.wdVisible), FBBoolToString(element.wdAccessible), element.wdRect[@"x"], element.wdRect[@"y"], element.wdRect[@"width"], element.wdRect[@"height"], element.wdIndex]; + NSString *expectedXml = [NSString stringWithFormat:@"\n<%@ type=\"%@\" value=\"%@\" name=\"%@\" label=\"%@\" enabled=\"%@\" visible=\"%@\" accessible=\"%@\" x=\"%@\" y=\"%@\" width=\"%@\" height=\"%@\" index=\"%lu\" placeholderValue=\"%@\" private_indexPath=\"top\"/>\n", + element.wdType, element.wdType, element.wdValue, element.wdName, element.wdLabel, FBBoolToString(element.wdEnabled), FBBoolToString(element.wdVisible), FBBoolToString(element.wdAccessible), element.wdRect[@"x"], element.wdRect[@"y"], element.wdRect[@"width"], element.wdRect[@"height"], element.wdIndex, element.wdPlaceholderValue]; XCTAssertTrue([resultXml isEqualToString: expectedXml]); } @@ -75,8 +75,8 @@ - (void)testtXPathPresentationWithSomeAttributesExcluded NSString *resultXml = [self xmlStringWithElement:element xpathQuery:nil excludingAttributes:@[@"type", @"visible", @"value", @"index"]]; - NSString *expectedXml = [NSString stringWithFormat:@"\n<%@ name=\"%@\" label=\"%@\" enabled=\"%@\" accessible=\"%@\" x=\"%@\" y=\"%@\" width=\"%@\" height=\"%@\" private_indexPath=\"top\"/>\n", - element.wdType, element.wdName, element.wdLabel, FBBoolToString(element.wdEnabled), FBBoolToString(element.wdAccessible), element.wdRect[@"x"], element.wdRect[@"y"], element.wdRect[@"width"], element.wdRect[@"height"]]; + NSString *expectedXml = [NSString stringWithFormat:@"\n<%@ name=\"%@\" label=\"%@\" enabled=\"%@\" accessible=\"%@\" x=\"%@\" y=\"%@\" width=\"%@\" height=\"%@\" placeholderValue=\"%@\" private_indexPath=\"top\"/>\n", + element.wdType, element.wdName, element.wdLabel, FBBoolToString(element.wdEnabled), FBBoolToString(element.wdAccessible), element.wdRect[@"x"], element.wdRect[@"y"], element.wdRect[@"width"], element.wdRect[@"height"], element.wdPlaceholderValue]; XCTAssertEqualObjects(resultXml, expectedXml); } @@ -89,8 +89,8 @@ - (void)testXPathPresentationBasedOnQueryMatchingAllAttributes NSString *resultXml = [self xmlStringWithElement:element xpathQuery:[NSString stringWithFormat:@"//%@[@*]", element.wdType] excludingAttributes:@[@"visible"]]; - NSString *expectedXml = [NSString stringWithFormat:@"\n<%@ type=\"%@\" value=\"%@\" name=\"%@\" label=\"%@\" enabled=\"%@\" visible=\"%@\" accessible=\"%@\" x=\"%@\" y=\"%@\" width=\"%@\" height=\"%@\" index=\"%lu\" hittable=\"%@\" private_indexPath=\"top\"/>\n", - element.wdType, element.wdType, @"йоло<>&"", element.wdName, @"a b", FBBoolToString(element.wdEnabled), FBBoolToString(element.wdVisible), FBBoolToString(element.wdAccessible), element.wdRect[@"x"], element.wdRect[@"y"], element.wdRect[@"width"], element.wdRect[@"height"], element.wdIndex, FBBoolToString(element.wdHittable)]; + NSString *expectedXml = [NSString stringWithFormat:@"\n<%@ type=\"%@\" value=\"%@\" name=\"%@\" label=\"%@\" enabled=\"%@\" visible=\"%@\" accessible=\"%@\" x=\"%@\" y=\"%@\" width=\"%@\" height=\"%@\" index=\"%lu\" hittable=\"%@\" placeholderValue=\"%@\" private_indexPath=\"top\"/>\n", + element.wdType, element.wdType, @"йоло<>&"", element.wdName, @"a b", FBBoolToString(element.wdEnabled), FBBoolToString(element.wdVisible), FBBoolToString(element.wdAccessible), element.wdRect[@"x"], element.wdRect[@"y"], element.wdRect[@"width"], element.wdRect[@"height"], element.wdIndex, FBBoolToString(element.wdHittable), element.wdPlaceholderValue]; XCTAssertEqualObjects(expectedXml, resultXml); } From f2de1a6e4baed7cce9a28a08d9b0998383c19e65 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 9 Mar 2025 08:40:23 +0000 Subject: [PATCH 047/219] chore(release): 9.1.0 [skip ci] ## [9.1.0](https://github.com/appium/WebDriverAgent/compare/v9.0.6...v9.1.0) (2025-03-09) ### Features * add placeholderValue ([#987](https://github.com/appium/WebDriverAgent/issues/987)) ([8c3a1cb](https://github.com/appium/WebDriverAgent/commit/8c3a1cb30655ed8d1a77d25bbeca71ee48c2ec3e)) --- CHANGELOG.md | 6 ++++++ WebDriverAgentLib/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 169152856..727a8d507 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [9.1.0](https://github.com/appium/WebDriverAgent/compare/v9.0.6...v9.1.0) (2025-03-09) + +### Features + +* add placeholderValue ([#987](https://github.com/appium/WebDriverAgent/issues/987)) ([8c3a1cb](https://github.com/appium/WebDriverAgent/commit/8c3a1cb30655ed8d1a77d25bbeca71ee48c2ec3e)) + ## [9.0.6](https://github.com/appium/WebDriverAgent/compare/v9.0.5...v9.0.6) (2025-02-28) ### Bug Fixes diff --git a/WebDriverAgentLib/Info.plist b/WebDriverAgentLib/Info.plist index 39be9a6fe..3bc3b1dc7 100644 --- a/WebDriverAgentLib/Info.plist +++ b/WebDriverAgentLib/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 9.0.6 + 9.1.0 CFBundleSignature ???? CFBundleVersion - 9.0.6 + 9.1.0 NSPrincipalClass diff --git a/package.json b/package.json index 95f0b1b33..ab880bb02 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "appium-webdriveragent", - "version": "9.0.6", + "version": "9.1.0", "description": "Package bundling WebDriverAgent", "main": "./build/index.js", "types": "./build/index.d.ts", From 9c9d8af9c98ba7b2843a42f54354b78e126d2d27 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Thu, 13 Mar 2025 22:01:25 +0100 Subject: [PATCH 048/219] feat: Add 'limitXpathContextScope' setting (#988) --- .github/workflows/functional-test.yml | 14 +-- .../Commands/FBSessionCommands.m | 4 + WebDriverAgentLib/Utilities/FBConfiguration.h | 8 ++ WebDriverAgentLib/Utilities/FBConfiguration.m | 12 ++ WebDriverAgentLib/Utilities/FBSettings.h | 1 + WebDriverAgentLib/Utilities/FBSettings.m | 1 + WebDriverAgentLib/Utilities/FBXPath-Private.h | 7 +- WebDriverAgentLib/Utilities/FBXPath.m | 119 ++++++++++++++---- .../FBXPathIntegrationTests.m | 23 ++++ WebDriverAgentTests/UnitTests/FBXPathTests.m | 16 +-- lib/webdriveragent.js | 4 +- test/unit/webdriveragent-specs.js | 8 +- 12 files changed, 165 insertions(+), 52 deletions(-) diff --git a/.github/workflows/functional-test.yml b/.github/workflows/functional-test.yml index b8c9855aa..524f337dc 100644 --- a/.github/workflows/functional-test.yml +++ b/.github/workflows/functional-test.yml @@ -13,17 +13,13 @@ jobs: matrix: test_targets: - HOST_OS: 'macos-15' - XCODE_VERSION: '16.1.0' - IOS_VERSION: '18.1' + XCODE_VERSION: '16.2' + IOS_VERSION: '18.2' IOS_MODEL: iPhone 16 Plus - - HOST_OS: 'macos-14' - XCODE_VERSION: '15.3' - IOS_VERSION: '17.4' + - HOST_OS: 'macos-15' + XCODE_VERSION: '15.4' + IOS_VERSION: '17.5' IOS_MODEL: iPhone 15 Plus - - HOST_OS: 'macos-13' - XCODE_VERSION: 14.3.1 - IOS_VERSION: '16.4' - IOS_MODEL: iPhone 14 Plus # https://github.com/actions/runner-images/blob/main/images/macos/macos-14-Readme.md runs-on: ${{matrix.test_targets.HOST_OS}} diff --git a/WebDriverAgentLib/Commands/FBSessionCommands.m b/WebDriverAgentLib/Commands/FBSessionCommands.m index 8f84d7afe..67b6b81e9 100644 --- a/WebDriverAgentLib/Commands/FBSessionCommands.m +++ b/WebDriverAgentLib/Commands/FBSessionCommands.m @@ -351,6 +351,7 @@ + (NSArray *)routes FB_SETTING_MAX_TYPING_FREQUENCY: @([FBConfiguration maxTypingFrequency]), FB_SETTING_RESPECT_SYSTEM_ALERTS: @([FBConfiguration shouldRespectSystemAlerts]), FB_SETTING_USE_CLEAR_TEXT_SHORTCUT: @([FBConfiguration useClearTextShortcut]), + FB_SETTING_LIMIT_XPATH_CONTEXT_SCOPE: @([FBConfiguration limitXpathContextScope]), #if !TARGET_OS_TV FB_SETTING_SCREENSHOT_ORIENTATION: [FBConfiguration humanReadableScreenshotOrientation], #endif @@ -445,6 +446,9 @@ + (NSArray *)routes if (nil != [settings objectForKey:FB_SETTING_USE_CLEAR_TEXT_SHORTCUT]) { [FBConfiguration setUseClearTextShortcut:[[settings objectForKey:FB_SETTING_USE_CLEAR_TEXT_SHORTCUT] boolValue]]; } + if (nil != [settings objectForKey:FB_SETTING_LIMIT_XPATH_CONTEXT_SCOPE]) { + [FBConfiguration setLimitXpathContextScope:[[settings objectForKey:FB_SETTING_LIMIT_XPATH_CONTEXT_SCOPE] boolValue]]; + } #if !TARGET_OS_TV if (nil != [settings objectForKey:FB_SETTING_SCREENSHOT_ORIENTATION]) { diff --git a/WebDriverAgentLib/Utilities/FBConfiguration.h b/WebDriverAgentLib/Utilities/FBConfiguration.h index ad9687b19..cb0a67dcf 100644 --- a/WebDriverAgentLib/Utilities/FBConfiguration.h +++ b/WebDriverAgentLib/Utilities/FBConfiguration.h @@ -103,6 +103,14 @@ extern NSString *const FBSnapshotMaxDepthKey; + (NSUInteger)mjpegServerFramerate; + (void)setMjpegServerFramerate:(NSUInteger)framerate; +/** + Whether to limit the XPath scope to descendant items only while performing a lookup + in an element context. Enabled by default. Being disabled, allows to use XPath locators + like ".." in order to match parent items of the current context root. + */ ++ (BOOL)limitXpathContextScope; ++ (void)setLimitXpathContextScope:(BOOL)enabled; + /** The quality of display screenshots. The higher quality you set is the bigger screenshot size is. The highest quality value is 0 (lossless PNG) or 3 (lossless HEIC). The lowest quality is 2 (highly compressed JPEG). diff --git a/WebDriverAgentLib/Utilities/FBConfiguration.m b/WebDriverAgentLib/Utilities/FBConfiguration.m index 1065b892e..f3cf8e42f 100644 --- a/WebDriverAgentLib/Utilities/FBConfiguration.m +++ b/WebDriverAgentLib/Utilities/FBConfiguration.m @@ -56,6 +56,7 @@ static BOOL FBShouldUseCompactResponses; static NSString *FBElementResponseAttributes; static BOOL FBUseClearTextShortcut; +static BOOL FBLimitXpathContextScope = YES; #if !TARGET_OS_TV static UIInterfaceOrientation FBScreenshotOrientation; #endif @@ -438,6 +439,16 @@ + (BOOL)useClearTextShortcut return FBUseClearTextShortcut; } ++ (BOOL)limitXpathContextScope +{ + return FBLimitXpathContextScope; +} + ++ (void)setLimitXpathContextScope:(BOOL)enabled +{ + FBLimitXpathContextScope = enabled; +} + #if !TARGET_OS_TV + (BOOL)setScreenshotOrientation:(NSString *)orientation error:(NSError **)error { @@ -503,6 +514,7 @@ + (void)resetSessionSettings // 50 should be enough for the majority of the cases. The performance is acceptable for values up to 100. FBSetCustomParameterForElementSnapshot(FBSnapshotMaxDepthKey, @50); FBUseClearTextShortcut = YES; + FBLimitXpathContextScope = YES; #if !TARGET_OS_TV FBScreenshotOrientation = UIInterfaceOrientationUnknown; #endif diff --git a/WebDriverAgentLib/Utilities/FBSettings.h b/WebDriverAgentLib/Utilities/FBSettings.h index 1a551c63f..7f6d57970 100644 --- a/WebDriverAgentLib/Utilities/FBSettings.h +++ b/WebDriverAgentLib/Utilities/FBSettings.h @@ -38,6 +38,7 @@ extern NSString* const FB_SETTING_ANIMATION_COOL_OFF_TIMEOUT; extern NSString* const FB_SETTING_MAX_TYPING_FREQUENCY; extern NSString* const FB_SETTING_RESPECT_SYSTEM_ALERTS; extern NSString* const FB_SETTING_USE_CLEAR_TEXT_SHORTCUT; +extern NSString* const FB_SETTING_LIMIT_XPATH_CONTEXT_SCOPE; NS_ASSUME_NONNULL_END diff --git a/WebDriverAgentLib/Utilities/FBSettings.m b/WebDriverAgentLib/Utilities/FBSettings.m index f5a61a8a8..c19889db3 100644 --- a/WebDriverAgentLib/Utilities/FBSettings.m +++ b/WebDriverAgentLib/Utilities/FBSettings.m @@ -34,3 +34,4 @@ NSString* const FB_SETTING_MAX_TYPING_FREQUENCY = @"maxTypingFrequency"; NSString* const FB_SETTING_RESPECT_SYSTEM_ALERTS = @"respectSystemAlerts"; NSString* const FB_SETTING_USE_CLEAR_TEXT_SHORTCUT = @"useClearTextShortcut"; +NSString* const FB_SETTING_LIMIT_XPATH_CONTEXT_SCOPE = @"limitXpathContextScope"; diff --git a/WebDriverAgentLib/Utilities/FBXPath-Private.h b/WebDriverAgentLib/Utilities/FBXPath-Private.h index 31bb403bf..7346b2c3f 100644 --- a/WebDriverAgentLib/Utilities/FBXPath-Private.h +++ b/WebDriverAgentLib/Utilities/FBXPath-Private.h @@ -25,7 +25,7 @@ NS_ASSUME_NONNULL_BEGIN If `query` argument is assigned then `excludedAttributes` argument is effectively ignored. @return zero if the method has completed successfully */ -+ (int)xmlRepresentationWithRootElement:(id)root ++ (int)xmlRepresentationWithRootElement:(id)root writer:(xmlTextWriterPtr)writer elementStore:(nullable NSMutableDictionary *)elementStore query:(nullable NSString*)query @@ -45,9 +45,12 @@ NS_ASSUME_NONNULL_BEGIN @param xpathQuery actual query. Should be valid XPath 1.0-compatible expression @param document libxml2-compatible document pointer + @param contextNode Optonal context node instance @return pointer to a libxml2-compatible structure with set of matched nodes or NULL in case of failure */ -+ (xmlXPathObjectPtr)evaluate:(NSString *)xpathQuery document:(xmlDocPtr)doc; ++ (xmlXPathObjectPtr)evaluate:(NSString *)xpathQuery + document:(xmlDocPtr)doc + contextNode:(nullable xmlNodePtr)contextNode; @end diff --git a/WebDriverAgentLib/Utilities/FBXPath.m b/WebDriverAgentLib/Utilities/FBXPath.m index d36291fdd..18793041f 100644 --- a/WebDriverAgentLib/Utilities/FBXPath.m +++ b/WebDriverAgentLib/Utilities/FBXPath.m @@ -11,6 +11,7 @@ #import "FBConfiguration.h" #import "FBExceptions.h" +#import "FBElementUtils.h" #import "FBLogger.h" #import "FBMacros.h" #import "FBXMLGenerationOptions.h" @@ -145,7 +146,7 @@ + (nullable NSString *)xmlStringWithRootElement:(id)root } if (rc >= 0) { - rc = [self xmlRepresentationWithRootElement:root + rc = [self xmlRepresentationWithRootElement:[self snapshotWithRoot:root] writer:writer elementStore:nil query:nil @@ -193,10 +194,29 @@ + (nullable NSString *)xmlStringWithRootElement:(id)root } NSMutableDictionary *elementStore = [NSMutableDictionary dictionary]; int rc = xmlTextWriterStartDocument(writer, NULL, _UTF8Encoding, NULL); + id lookupScopeSnapshot = nil; + id contextRootSnapshot = nil; if (rc < 0) { [FBLogger logFmt:@"Failed to invoke libxml2>xmlTextWriterStartDocument. Error code: %d", rc]; } else { - rc = [self xmlRepresentationWithRootElement:root + if (FBConfiguration.limitXpathContextScope) { + lookupScopeSnapshot = [self snapshotWithRoot:root]; + } else { + if ([root isKindOfClass:XCUIElement.class]) { + lookupScopeSnapshot = [self snapshotWithRoot:[(XCUIElement *)root application]]; + contextRootSnapshot = [root isKindOfClass:XCUIApplication.class] + ? nil + : [(XCUIElement *)root fb_takeSnapshot:YES]; + } else { + lookupScopeSnapshot = (id)root; + contextRootSnapshot = nil == lookupScopeSnapshot.parent ? nil : (id)root; + while (nil != lookupScopeSnapshot.parent) { + lookupScopeSnapshot = lookupScopeSnapshot.parent; + } + } + } + + rc = [self xmlRepresentationWithRootElement:lookupScopeSnapshot writer:writer elementStore:elementStore query:xpathQuery @@ -214,7 +234,22 @@ + (nullable NSString *)xmlStringWithRootElement:(id)root return [self throwException:FBXPathQueryEvaluationException forQuery:xpathQuery]; } - xmlXPathObjectPtr queryResult = [self evaluate:xpathQuery document:doc]; + xmlXPathObjectPtr contextNodeQueryResult = [self matchNodeInDocument:doc + elementStore:elementStore.copy + forSnapshot:contextRootSnapshot]; + xmlNodePtr contextNode = NULL; + if (NULL != contextNodeQueryResult) { + xmlNodeSetPtr nodeSet = contextNodeQueryResult->nodesetval; + if (!xmlXPathNodeSetIsEmpty(nodeSet)) { + contextNode = nodeSet->nodeTab[0]; + } + } + xmlXPathObjectPtr queryResult = [self evaluate:xpathQuery + document:doc + contextNode:contextNode]; + if (NULL != contextNodeQueryResult) { + xmlXPathFreeObject(contextNodeQueryResult); + } if (NULL == queryResult) { xmlFreeTextWriter(writer); xmlFreeDoc(doc); @@ -256,6 +291,36 @@ + (NSArray *)collectMatchingSnapshots:(xmlNodeSetPtr)nodeSet return matchingSnapshots.copy; } ++ (nullable xmlXPathObjectPtr)matchNodeInDocument:(xmlDocPtr)doc + elementStore:(NSDictionary> *)elementStore + forSnapshot:(nullable id)snapshot +{ + if (nil == snapshot) { + return NULL; + } + + NSString *contextRootUid = [FBElementUtils uidWithAccessibilityElement:[(id)snapshot accessibilityElement]]; + if (nil == contextRootUid) { + return NULL; + } + + for (NSString *key in elementStore) { + id value = [elementStore objectForKey:key]; + NSString *snapshotUid = [FBElementUtils uidWithAccessibilityElement:[value accessibilityElement]]; + if (nil == snapshotUid || ![snapshotUid isEqualToString:contextRootUid]) { + continue; + } + NSString *indexQuery = [NSString stringWithFormat:@"//*[@%@=\"%@\"]", kXMLIndexPathKey, key]; + xmlXPathObjectPtr queryResult = [self evaluate:indexQuery + document:doc + contextNode:NULL]; + if (NULL != queryResult) { + return queryResult; + } + } + return NULL; +} + + (NSSet *)elementAttributesWithXPathQuery:(NSString *)query { if ([query rangeOfString:@"[^\\w@]@\\*[^\\w]" options:NSRegularExpressionSearch].location != NSNotFound) { @@ -271,7 +336,7 @@ + (NSArray *)collectMatchingSnapshots:(xmlNodeSetPtr)nodeSet return result.copy; } -+ (int)xmlRepresentationWithRootElement:(id)root ++ (int)xmlRepresentationWithRootElement:(id)root writer:(xmlTextWriterPtr)writer elementStore:(nullable NSMutableDictionary *)elementStore query:(nullable NSString*)query @@ -312,14 +377,16 @@ + (int)xmlRepresentationWithRootElement:(id)root return 0; } -+ (xmlXPathObjectPtr)evaluate:(NSString *)xpathQuery document:(xmlDocPtr)doc ++ (xmlXPathObjectPtr)evaluate:(NSString *)xpathQuery + document:(xmlDocPtr)doc + contextNode:(nullable xmlNodePtr)contextNode { xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc); if (NULL == xpathCtx) { [FBLogger logFmt:@"Failed to invoke libxml2>xmlXPathNewContext for XPath query \"%@\"", xpathQuery]; return NULL; } - xpathCtx->node = doc->children; + xpathCtx->node = NULL == contextNode ? doc->children : contextNode; xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression((const xmlChar *)[xpathQuery UTF8String], xpathCtx); if (NULL == xpathObj) { @@ -360,7 +427,7 @@ + (int)recordElementAttributes:(xmlTextWriterPtr)writer return 0; } -+ (int)writeXmlWithRootElement:(id)root ++ (int)writeXmlWithRootElement:(id)root indexPath:(nullable NSString *)indexPath elementStore:(nullable NSMutableDictionary *)elementStore includedAttributes:(nullable NSSet *)includedAttributes @@ -368,29 +435,13 @@ + (int)writeXmlWithRootElement:(id)root { NSAssert((indexPath == nil && elementStore == nil) || (indexPath != nil && elementStore != nil), @"Either both or none of indexPath and elementStore arguments should be equal to nil", nil); - __block id currentSnapshot; - NSArray> *children; - if ([root isKindOfClass:XCUIElement.class]) { - XCUIElement *element = (XCUIElement *)root; - if (nil == includedAttributes || [includedAttributes containsObject:FBVisibleAttribute.class]) { - // If the app is not idle state while we retrieve the visiblity state - // then the snapshot retrieval operation might freeze and time out - [element.application fb_waitUntilStableWithTimeout:FBConfiguration.animationCoolOffTimeout]; - } - @autoreleasepool { - currentSnapshot = [element fb_takeSnapshot:YES]; - } - children = currentSnapshot.children; - } else { - currentSnapshot = (id)root; - children = currentSnapshot.children; - } + NSArray> *children = root.children; if (elementStore != nil && indexPath != nil && [indexPath isEqualToString:topNodeIndexPath]) { - [elementStore setObject:currentSnapshot forKey:topNodeIndexPath]; + [elementStore setObject:root forKey:topNodeIndexPath]; } - FBXCElementSnapshotWrapper *wrappedSnapshot = [FBXCElementSnapshotWrapper ensureWrapped:currentSnapshot]; + FBXCElementSnapshotWrapper *wrappedSnapshot = [FBXCElementSnapshotWrapper ensureWrapped:root]; int rc = xmlTextWriterStartElement(writer, (xmlChar *)[wrappedSnapshot.wdType UTF8String]); if (rc < 0) { [FBLogger logFmt:@"Failed to invoke libxml2>xmlTextWriterStartElement for the tag value '%@'. Error code: %d", wrappedSnapshot.wdType, rc]; @@ -398,7 +449,7 @@ + (int)writeXmlWithRootElement:(id)root } rc = [self recordElementAttributes:writer - forElement:currentSnapshot + forElement:root indexPath:indexPath includedAttributes:includedAttributes]; if (rc < 0) { @@ -431,6 +482,20 @@ + (int)writeXmlWithRootElement:(id)root return 0; } ++ (id)snapshotWithRoot:(id)root +{ + if (![root isKindOfClass:XCUIElement.class]) { + return (id)root; + } + + // If the app is not idle state while we retrieve the visiblity state + // then the snapshot retrieval operation might freeze and time out + [[(XCUIElement *)root application] fb_waitUntilStableWithTimeout:FBConfiguration.animationCoolOffTimeout]; + @autoreleasepool { + return [(XCUIElement *)root fb_takeSnapshot:YES]; + } +} + @end diff --git a/WebDriverAgentTests/IntegrationTests/FBXPathIntegrationTests.m b/WebDriverAgentTests/IntegrationTests/FBXPathIntegrationTests.m index adbadeb32..77b3c2bcf 100644 --- a/WebDriverAgentTests/IntegrationTests/FBXPathIntegrationTests.m +++ b/WebDriverAgentTests/IntegrationTests/FBXPathIntegrationTests.m @@ -96,6 +96,29 @@ - (void)testFindMatchesInElement } } +- (void)testFindMatchesWithoutContextScopeLimit +{ + XCUIElement *button = self.testedApplication.buttons.firstMatch; + BOOL previousValue = FBConfiguration.limitXpathContextScope; + FBConfiguration.limitXpathContextScope = NO; + @try { + NSArray *parentSnapshots = [FBXPath matchesWithRootElement:button forQuery:@".."]; + XCTAssertEqual(parentSnapshots.count, 1); + XCTAssertEqualObjects( + [FBXCElementSnapshotWrapper ensureWrapped:[parentSnapshots objectAtIndex:0]].wdLabel, + @"MainView" + ); + NSArray *currentSnapshots = [FBXPath matchesWithRootElement:button forQuery:@"."]; + XCTAssertEqual(currentSnapshots.count, 1); + XCTAssertEqualObjects( + [FBXCElementSnapshotWrapper ensureWrapped:[currentSnapshots objectAtIndex:0]].wdType, + @"XCUIElementTypeButton" + ); + } @finally { + FBConfiguration.limitXpathContextScope = previousValue; + } +} + - (void)testFindMatchesInElementWithDotNotation { NSArray> *matchingSnapshots = [FBXPath matchesWithRootElement:self.testedApplication forQuery:@".//XCUIElementTypeButton"]; diff --git a/WebDriverAgentTests/UnitTests/FBXPathTests.m b/WebDriverAgentTests/UnitTests/FBXPathTests.m index ad0d1988f..3d549e0b2 100644 --- a/WebDriverAgentTests/UnitTests/FBXPathTests.m +++ b/WebDriverAgentTests/UnitTests/FBXPathTests.m @@ -21,7 +21,7 @@ @interface FBXPathTests : XCTestCase @implementation FBXPathTests -- (NSString *)xmlStringWithElement:(id)element +- (NSString *)xmlStringWithElement:(id)snapshot xpathQuery:(nullable NSString *)query excludingAttributes:(nullable NSArray *)excludedAttributes { @@ -33,7 +33,7 @@ - (NSString *)xmlStringWithElement:(id)element xmlChar *xmlbuff = NULL; int rc = xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL); if (rc >= 0) { - rc = [FBXPath xmlRepresentationWithRootElement:element + rc = [FBXPath xmlRepresentationWithRootElement:snapshot writer:writer elementStore:elementStore query:query @@ -60,7 +60,7 @@ - (void)testDefaultXPathPresentation { XCElementSnapshotDouble *snapshot = [XCElementSnapshotDouble new]; id element = (id)[FBXCElementSnapshotWrapper ensureWrapped:(id)snapshot]; - NSString *resultXml = [self xmlStringWithElement:element + NSString *resultXml = [self xmlStringWithElement:(id)element xpathQuery:nil excludingAttributes:nil]; NSString *expectedXml = [NSString stringWithFormat:@"\n<%@ type=\"%@\" value=\"%@\" name=\"%@\" label=\"%@\" enabled=\"%@\" visible=\"%@\" accessible=\"%@\" x=\"%@\" y=\"%@\" width=\"%@\" height=\"%@\" index=\"%lu\" placeholderValue=\"%@\" private_indexPath=\"top\"/>\n", @@ -72,7 +72,7 @@ - (void)testtXPathPresentationWithSomeAttributesExcluded { XCElementSnapshotDouble *snapshot = [XCElementSnapshotDouble new]; id element = (id)[FBXCElementSnapshotWrapper ensureWrapped:(id)snapshot]; - NSString *resultXml = [self xmlStringWithElement:element + NSString *resultXml = [self xmlStringWithElement:(id)element xpathQuery:nil excludingAttributes:@[@"type", @"visible", @"value", @"index"]]; NSString *expectedXml = [NSString stringWithFormat:@"\n<%@ name=\"%@\" label=\"%@\" enabled=\"%@\" accessible=\"%@\" x=\"%@\" y=\"%@\" width=\"%@\" height=\"%@\" placeholderValue=\"%@\" private_indexPath=\"top\"/>\n", @@ -86,7 +86,7 @@ - (void)testXPathPresentationBasedOnQueryMatchingAllAttributes snapshot.value = @"йоло<>&\""; snapshot.label = @"a\nb"; id element = (id)[FBXCElementSnapshotWrapper ensureWrapped:(id)snapshot]; - NSString *resultXml = [self xmlStringWithElement:element + NSString *resultXml = [self xmlStringWithElement:(id)element xpathQuery:[NSString stringWithFormat:@"//%@[@*]", element.wdType] excludingAttributes:@[@"visible"]]; NSString *expectedXml = [NSString stringWithFormat:@"\n<%@ type=\"%@\" value=\"%@\" name=\"%@\" label=\"%@\" enabled=\"%@\" visible=\"%@\" accessible=\"%@\" x=\"%@\" y=\"%@\" width=\"%@\" height=\"%@\" index=\"%lu\" hittable=\"%@\" placeholderValue=\"%@\" private_indexPath=\"top\"/>\n", @@ -98,7 +98,7 @@ - (void)testXPathPresentationBasedOnQueryMatchingSomeAttributes { XCElementSnapshotDouble *snapshot = [XCElementSnapshotDouble new]; id element = (id)[FBXCElementSnapshotWrapper ensureWrapped:(id)snapshot]; - NSString *resultXml = [self xmlStringWithElement:element + NSString *resultXml = [self xmlStringWithElement:(id)element xpathQuery:[NSString stringWithFormat:@"//%@[@%@ and contains(@%@, 'blabla')]", element.wdType, @"value", @"name"] excludingAttributes:nil]; NSString *expectedXml = [NSString stringWithFormat:@"\n<%@ value=\"%@\" name=\"%@\" private_indexPath=\"top\"/>\n", @@ -117,7 +117,7 @@ - (void)testSnapshotXPathResultsMatching NSString *query = [NSString stringWithFormat:@"//%@", root.wdType]; int rc = xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL); if (rc >= 0) { - rc = [FBXPath xmlRepresentationWithRootElement:root + rc = [FBXPath xmlRepresentationWithRootElement:(id)root writer:writer elementStore:elementStore query:query @@ -132,7 +132,7 @@ - (void)testSnapshotXPathResultsMatching XCTFail(@"Unable to create the source XML document"); } - xmlXPathObjectPtr queryResult = [FBXPath evaluate:query document:doc]; + xmlXPathObjectPtr queryResult = [FBXPath evaluate:query document:doc contextNode:NULL]; if (NULL == queryResult) { xmlFreeTextWriter(writer); xmlFreeDoc(doc); diff --git a/lib/webdriveragent.js b/lib/webdriveragent.js index a2a9dbb0d..73b056bd5 100644 --- a/lib/webdriveragent.js +++ b/lib/webdriveragent.js @@ -579,8 +579,8 @@ export class WebDriverAgent { setupProxies (sessionId) { const proxyOpts = { log: this.log, - server: this.url.hostname, - port: this.url.port, + server: this.url.hostname ?? undefined, + port: parseInt(this.url.port ?? '', 10) || undefined, base: this.basePath, timeout: this.wdaConnectionTimeout, keepAlive: true, diff --git a/test/unit/webdriveragent-specs.js b/test/unit/webdriveragent-specs.js index 1b844e08a..487f71d91 100644 --- a/test/unit/webdriveragent-specs.js +++ b/test/unit/webdriveragent-specs.js @@ -71,10 +71,10 @@ describe('launch', function () { await agent.launch('sessionId').should.eventually.eql({build: 'data'}); agent.url.href.should.eql(override); agent.jwproxy.server.should.eql('mockurl'); - agent.jwproxy.port.should.eql('8100'); + agent.jwproxy.port.should.eql(8100); agent.jwproxy.base.should.eql(''); agent.noSessionProxy.server.should.eql('mockurl'); - agent.noSessionProxy.port.should.eql('8100'); + agent.noSessionProxy.port.should.eql(8100); agent.noSessionProxy.base.should.eql(''); wdaStub.reset(); }); @@ -97,10 +97,10 @@ describe('use wda proxy url', function () { agent.url.hostname.should.eql('127.0.0.1'); agent.url.path.should.eql('/aabbccdd'); agent.jwproxy.server.should.eql('127.0.0.1'); - agent.jwproxy.port.should.eql('8100'); + agent.jwproxy.port.should.eql(8100); agent.jwproxy.base.should.eql('/aabbccdd'); agent.noSessionProxy.server.should.eql('127.0.0.1'); - agent.noSessionProxy.port.should.eql('8100'); + agent.noSessionProxy.port.should.eql(8100); agent.noSessionProxy.base.should.eql('/aabbccdd'); }); }); From fd7291306ebdda67af3df042a5a2b50478b377fe Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 13 Mar 2025 21:09:06 +0000 Subject: [PATCH 049/219] chore(release): 9.2.0 [skip ci] ## [9.2.0](https://github.com/appium/WebDriverAgent/compare/v9.1.0...v9.2.0) (2025-03-13) ### Features * Add 'limitXpathContextScope' setting ([#988](https://github.com/appium/WebDriverAgent/issues/988)) ([9c9d8af](https://github.com/appium/WebDriverAgent/commit/9c9d8af9c98ba7b2843a42f54354b78e126d2d27)) --- CHANGELOG.md | 6 ++++++ WebDriverAgentLib/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 727a8d507..3f0728088 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [9.2.0](https://github.com/appium/WebDriverAgent/compare/v9.1.0...v9.2.0) (2025-03-13) + +### Features + +* Add 'limitXpathContextScope' setting ([#988](https://github.com/appium/WebDriverAgent/issues/988)) ([9c9d8af](https://github.com/appium/WebDriverAgent/commit/9c9d8af9c98ba7b2843a42f54354b78e126d2d27)) + ## [9.1.0](https://github.com/appium/WebDriverAgent/compare/v9.0.6...v9.1.0) (2025-03-09) ### Features diff --git a/WebDriverAgentLib/Info.plist b/WebDriverAgentLib/Info.plist index 3bc3b1dc7..af208b64c 100644 --- a/WebDriverAgentLib/Info.plist +++ b/WebDriverAgentLib/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 9.1.0 + 9.2.0 CFBundleSignature ???? CFBundleVersion - 9.1.0 + 9.2.0 NSPrincipalClass diff --git a/package.json b/package.json index ab880bb02..22a37b149 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "appium-webdriveragent", - "version": "9.1.0", + "version": "9.2.0", "description": "Package bundling WebDriverAgent", "main": "./build/index.js", "types": "./build/index.d.ts", From 34f95107997bdec63219a2fd917de899de3e198c Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Fri, 21 Mar 2025 07:44:15 +0100 Subject: [PATCH 050/219] feat: Add /window/rect W3C endpoint (#991) --- .../Commands/FBElementCommands.m | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/WebDriverAgentLib/Commands/FBElementCommands.m b/WebDriverAgentLib/Commands/FBElementCommands.m index a03fbea41..adcfa6ed6 100644 --- a/WebDriverAgentLib/Commands/FBElementCommands.m +++ b/WebDriverAgentLib/Commands/FBElementCommands.m @@ -53,6 +53,7 @@ + (NSArray *)routes return @[ [[FBRoute GET:@"/window/size"] respondWithTarget:self action:@selector(handleGetWindowSize:)], + [[FBRoute GET:@"/window/rect"] respondWithTarget:self action:@selector(handleGetWindowRect:)], [[FBRoute GET:@"/window/size"].withoutSession respondWithTarget:self action:@selector(handleGetWindowSize:)], [[FBRoute GET:@"/element/:uuid/enabled"] respondWithTarget:self action:@selector(handleGetEnabled:)], [[FBRoute GET:@"/element/:uuid/rect"] respondWithTarget:self action:@selector(handleGetRect:)], @@ -525,13 +526,32 @@ + (NSArray *)routes { XCUIApplication *app = request.session.activeApplication ?: XCUIApplication.fb_activeApplication; + CGRect frame = app.wdFrame; #if TARGET_OS_TV - CGSize screenSize = app.frame.size; + CGSize screenSize = frame.size; #else + CGSize screenSize = FBAdjustDimensionsForApplication(frame.size, app.interfaceOrientation); +#endif + return FBResponseWithObject(@{ + @"width": @(screenSize.width), + @"height": @(screenSize.height), + }); +} + + ++ (id)handleGetWindowRect:(FBRouteRequest *)request +{ + XCUIApplication *app = request.session.activeApplication ?: XCUIApplication.fb_activeApplication; + CGRect frame = app.wdFrame; +#if TARGET_OS_TV + CGSize screenSize = frame.size; +#else CGSize screenSize = FBAdjustDimensionsForApplication(frame.size, app.interfaceOrientation); #endif return FBResponseWithObject(@{ + @"x": @(frame.origin.x), + @"y": @(frame.origin.y), @"width": @(screenSize.width), @"height": @(screenSize.height), }); From d84ca5c6b2eb156dbada56e928ab78483bbfdb4f Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 21 Mar 2025 06:48:27 +0000 Subject: [PATCH 051/219] chore(release): 9.3.0 [skip ci] ## [9.3.0](https://github.com/appium/WebDriverAgent/compare/v9.2.0...v9.3.0) (2025-03-21) ### Features * Add /window/rect W3C endpoint ([#991](https://github.com/appium/WebDriverAgent/issues/991)) ([34f9510](https://github.com/appium/WebDriverAgent/commit/34f95107997bdec63219a2fd917de899de3e198c)) --- CHANGELOG.md | 6 ++++++ WebDriverAgentLib/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f0728088..5a0f9f843 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [9.3.0](https://github.com/appium/WebDriverAgent/compare/v9.2.0...v9.3.0) (2025-03-21) + +### Features + +* Add /window/rect W3C endpoint ([#991](https://github.com/appium/WebDriverAgent/issues/991)) ([34f9510](https://github.com/appium/WebDriverAgent/commit/34f95107997bdec63219a2fd917de899de3e198c)) + ## [9.2.0](https://github.com/appium/WebDriverAgent/compare/v9.1.0...v9.2.0) (2025-03-13) ### Features diff --git a/WebDriverAgentLib/Info.plist b/WebDriverAgentLib/Info.plist index af208b64c..2b7c6a296 100644 --- a/WebDriverAgentLib/Info.plist +++ b/WebDriverAgentLib/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 9.2.0 + 9.3.0 CFBundleSignature ???? CFBundleVersion - 9.2.0 + 9.3.0 NSPrincipalClass diff --git a/package.json b/package.json index 22a37b149..c6379c210 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "appium-webdriveragent", - "version": "9.2.0", + "version": "9.3.0", "description": "Package bundling WebDriverAgent", "main": "./build/index.js", "types": "./build/index.d.ts", From f55462f4fa63314dfea48670d17ee54dc5fe2d96 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Mar 2025 15:43:43 +0100 Subject: [PATCH 052/219] chore(deps-dev): bump sinon from 19.0.5 to 20.0.0 (#994) Bumps [sinon](https://github.com/sinonjs/sinon) from 19.0.5 to 20.0.0. - [Release notes](https://github.com/sinonjs/sinon/releases) - [Changelog](https://github.com/sinonjs/sinon/blob/main/docs/changelog.md) - [Commits](https://github.com/sinonjs/sinon/compare/v19.0.5...v20.0.0) --- updated-dependencies: - dependency-name: sinon dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c6379c210..262f29661 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "prettier": "^3.0.0", "semantic-release": "^24.0.0", "semver": "^7.3.7", - "sinon": "^19.0.1", + "sinon": "^20.0.0", "ts-node": "^10.9.1", "typescript": "^5.4.2" }, From c016c7c17229803d80c7fe40b79078abb39c11be Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 25 Mar 2025 14:48:58 +0000 Subject: [PATCH 053/219] chore(release): 9.3.1 [skip ci] ## [9.3.1](https://github.com/appium/WebDriverAgent/compare/v9.3.0...v9.3.1) (2025-03-25) ### Miscellaneous Chores * **deps-dev:** bump sinon from 19.0.5 to 20.0.0 ([#994](https://github.com/appium/WebDriverAgent/issues/994)) ([f55462f](https://github.com/appium/WebDriverAgent/commit/f55462f4fa63314dfea48670d17ee54dc5fe2d96)) --- CHANGELOG.md | 6 ++++++ WebDriverAgentLib/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a0f9f843..fb9871eb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [9.3.1](https://github.com/appium/WebDriverAgent/compare/v9.3.0...v9.3.1) (2025-03-25) + +### Miscellaneous Chores + +* **deps-dev:** bump sinon from 19.0.5 to 20.0.0 ([#994](https://github.com/appium/WebDriverAgent/issues/994)) ([f55462f](https://github.com/appium/WebDriverAgent/commit/f55462f4fa63314dfea48670d17ee54dc5fe2d96)) + ## [9.3.0](https://github.com/appium/WebDriverAgent/compare/v9.2.0...v9.3.0) (2025-03-21) ### Features diff --git a/WebDriverAgentLib/Info.plist b/WebDriverAgentLib/Info.plist index 2b7c6a296..b87c79309 100644 --- a/WebDriverAgentLib/Info.plist +++ b/WebDriverAgentLib/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 9.3.0 + 9.3.1 CFBundleSignature ???? CFBundleVersion - 9.3.0 + 9.3.1 NSPrincipalClass diff --git a/package.json b/package.json index 262f29661..8930ec7dd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "appium-webdriveragent", - "version": "9.3.0", + "version": "9.3.1", "description": "Package bundling WebDriverAgent", "main": "./build/index.js", "types": "./build/index.d.ts", From 9789e393b55bc682a9a8ef5a65fba5e4dbf752ce Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Wed, 26 Mar 2025 22:31:35 +0100 Subject: [PATCH 054/219] fix: Adjust limitXPathContextScope setting name (#995) --- WebDriverAgentLib/Utilities/FBSettings.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WebDriverAgentLib/Utilities/FBSettings.m b/WebDriverAgentLib/Utilities/FBSettings.m index c19889db3..d91e343ed 100644 --- a/WebDriverAgentLib/Utilities/FBSettings.m +++ b/WebDriverAgentLib/Utilities/FBSettings.m @@ -34,4 +34,4 @@ NSString* const FB_SETTING_MAX_TYPING_FREQUENCY = @"maxTypingFrequency"; NSString* const FB_SETTING_RESPECT_SYSTEM_ALERTS = @"respectSystemAlerts"; NSString* const FB_SETTING_USE_CLEAR_TEXT_SHORTCUT = @"useClearTextShortcut"; -NSString* const FB_SETTING_LIMIT_XPATH_CONTEXT_SCOPE = @"limitXpathContextScope"; +NSString* const FB_SETTING_LIMIT_XPATH_CONTEXT_SCOPE = @"limitXPathContextScope"; From bd07a10a26515f2c4051954eff93c08543166d26 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 26 Mar 2025 21:38:12 +0000 Subject: [PATCH 055/219] chore(release): 9.3.2 [skip ci] ## [9.3.2](https://github.com/appium/WebDriverAgent/compare/v9.3.1...v9.3.2) (2025-03-26) ### Bug Fixes * Adjust limitXPathContextScope setting name ([#995](https://github.com/appium/WebDriverAgent/issues/995)) ([9789e39](https://github.com/appium/WebDriverAgent/commit/9789e393b55bc682a9a8ef5a65fba5e4dbf752ce)) --- CHANGELOG.md | 6 ++++++ WebDriverAgentLib/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb9871eb1..992cec5f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [9.3.2](https://github.com/appium/WebDriverAgent/compare/v9.3.1...v9.3.2) (2025-03-26) + +### Bug Fixes + +* Adjust limitXPathContextScope setting name ([#995](https://github.com/appium/WebDriverAgent/issues/995)) ([9789e39](https://github.com/appium/WebDriverAgent/commit/9789e393b55bc682a9a8ef5a65fba5e4dbf752ce)) + ## [9.3.1](https://github.com/appium/WebDriverAgent/compare/v9.3.0...v9.3.1) (2025-03-25) ### Miscellaneous Chores diff --git a/WebDriverAgentLib/Info.plist b/WebDriverAgentLib/Info.plist index b87c79309..c22fd58da 100644 --- a/WebDriverAgentLib/Info.plist +++ b/WebDriverAgentLib/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 9.3.1 + 9.3.2 CFBundleSignature ???? CFBundleVersion - 9.3.1 + 9.3.2 NSPrincipalClass diff --git a/package.json b/package.json index 8930ec7dd..1bdaf194b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "appium-webdriveragent", - "version": "9.3.1", + "version": "9.3.2", "description": "Package bundling WebDriverAgent", "main": "./build/index.js", "types": "./build/index.d.ts", From 03ca7cd27b7cd92a45b344eb661db973c5dde809 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Thu, 27 Mar 2025 12:14:00 +0100 Subject: [PATCH 056/219] fix: Properly set snapshot lookup scope if limitXpathContextScope is disabled (#996) --- WebDriverAgentLib/Categories/XCUIElement+FBFind.m | 6 ++++-- .../IntegrationTests/FBXPathIntegrationTests.m | 12 ++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBFind.m b/WebDriverAgentLib/Categories/XCUIElement+FBFind.m index d33fce1ea..138119da2 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBFind.m +++ b/WebDriverAgentLib/Categories/XCUIElement+FBFind.m @@ -12,6 +12,7 @@ #import "FBMacros.h" #import "FBElementTypeTransformer.h" +#import "FBConfiguration.h" #import "NSPredicate+FBFormat.h" #import "FBXCElementSnapshotWrapper+Helpers.h" #import "FBXCodeCompatibility.h" @@ -109,8 +110,9 @@ @implementation XCUIElement (FBFind) id snapshot = matchingSnapshots.firstObject; matchingSnapshots = @[snapshot]; } - return [self fb_filterDescendantsWithSnapshots:matchingSnapshots - onlyChildren:NO]; + XCUIElement *scopeRoot = FBConfiguration.limitXpathContextScope ? self : self.application; + return [scopeRoot fb_filterDescendantsWithSnapshots:matchingSnapshots + onlyChildren:NO]; } diff --git a/WebDriverAgentTests/IntegrationTests/FBXPathIntegrationTests.m b/WebDriverAgentTests/IntegrationTests/FBXPathIntegrationTests.m index 77b3c2bcf..adaca291a 100644 --- a/WebDriverAgentTests/IntegrationTests/FBXPathIntegrationTests.m +++ b/WebDriverAgentTests/IntegrationTests/FBXPathIntegrationTests.m @@ -108,12 +108,24 @@ - (void)testFindMatchesWithoutContextScopeLimit [FBXCElementSnapshotWrapper ensureWrapped:[parentSnapshots objectAtIndex:0]].wdLabel, @"MainView" ); + NSArray *elements = [button.application fb_filterDescendantsWithSnapshots:parentSnapshots onlyChildren:NO]; + XCTAssertEqual(elements.count, 1); + XCTAssertEqualObjects( + [[elements objectAtIndex:0] wdLabel], + @"MainView" + ); NSArray *currentSnapshots = [FBXPath matchesWithRootElement:button forQuery:@"."]; XCTAssertEqual(currentSnapshots.count, 1); XCTAssertEqualObjects( [FBXCElementSnapshotWrapper ensureWrapped:[currentSnapshots objectAtIndex:0]].wdType, @"XCUIElementTypeButton" ); + NSArray *currentElements = [button.application fb_filterDescendantsWithSnapshots:currentSnapshots onlyChildren:NO]; + XCTAssertEqual(currentElements.count, 1); + XCTAssertEqualObjects( + [[currentElements objectAtIndex:0] wdType], + @"XCUIElementTypeButton" + ); } @finally { FBConfiguration.limitXpathContextScope = previousValue; } From 5f91803d41634713bda8be43955c35c6c31645cb Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 27 Mar 2025 11:19:12 +0000 Subject: [PATCH 057/219] chore(release): 9.3.3 [skip ci] ## [9.3.3](https://github.com/appium/WebDriverAgent/compare/v9.3.2...v9.3.3) (2025-03-27) ### Bug Fixes * Properly set snapshot lookup scope if limitXpathContextScope is disabled ([#996](https://github.com/appium/WebDriverAgent/issues/996)) ([03ca7cd](https://github.com/appium/WebDriverAgent/commit/03ca7cd27b7cd92a45b344eb661db973c5dde809)) --- CHANGELOG.md | 6 ++++++ WebDriverAgentLib/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 992cec5f9..a6c43dec8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [9.3.3](https://github.com/appium/WebDriverAgent/compare/v9.3.2...v9.3.3) (2025-03-27) + +### Bug Fixes + +* Properly set snapshot lookup scope if limitXpathContextScope is disabled ([#996](https://github.com/appium/WebDriverAgent/issues/996)) ([03ca7cd](https://github.com/appium/WebDriverAgent/commit/03ca7cd27b7cd92a45b344eb661db973c5dde809)) + ## [9.3.2](https://github.com/appium/WebDriverAgent/compare/v9.3.1...v9.3.2) (2025-03-26) ### Bug Fixes diff --git a/WebDriverAgentLib/Info.plist b/WebDriverAgentLib/Info.plist index c22fd58da..ee71d3bf5 100644 --- a/WebDriverAgentLib/Info.plist +++ b/WebDriverAgentLib/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 9.3.2 + 9.3.3 CFBundleSignature ???? CFBundleVersion - 9.3.2 + 9.3.3 NSPrincipalClass diff --git a/package.json b/package.json index 1bdaf194b..e0d86fe30 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "appium-webdriveragent", - "version": "9.3.2", + "version": "9.3.3", "description": "Package bundling WebDriverAgent", "main": "./build/index.js", "types": "./build/index.d.ts", From 60f5aeffdda85faffd60aba416dc9d92987f19ac Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Wed, 2 Apr 2025 07:42:15 +0200 Subject: [PATCH 058/219] feat: Always apply the native snapshotting strategy for XCUIApplication instances (#998) --- .../Categories/XCUIElement+FBUtilities.m | 2 +- .../XCUIApplicationHelperTests.m | 23 ++++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m b/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m index 26e274c18..529e17b54 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m +++ b/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m @@ -49,7 +49,7 @@ @implementation XCUIElement (FBUtilities) __block id snapshot = nil; @autoreleasepool { NSError *error = nil; - snapshot = inDepth + snapshot = inDepth && ![self isKindOfClass:XCUIApplication.class] ? [self.fb_query fb_uniqueSnapshotWithError:&error] : (id)[self snapshotWithError:&error]; if (nil == snapshot) { diff --git a/WebDriverAgentTests/IntegrationTests/XCUIApplicationHelperTests.m b/WebDriverAgentTests/IntegrationTests/XCUIApplicationHelperTests.m index 794be2192..b6ed3e07b 100644 --- a/WebDriverAgentTests/IntegrationTests/XCUIApplicationHelperTests.m +++ b/WebDriverAgentTests/IntegrationTests/XCUIApplicationHelperTests.m @@ -20,6 +20,23 @@ #import "XCUIElement+FBIsVisible.h" #import "FBXCodeCompatibility.h" +void calculateMaxTreeDepth(NSDictionary *tree, NSNumber *currentDepth, NSNumber** maxDepth) { + if (nil == maxDepth) { + return; + } + + NSArray *children = tree[@"children"]; + if (nil == children || 0 == children.count) { + return; + } + for (NSDictionary *child in children) { + if (currentDepth.integerValue > [*maxDepth integerValue]) { + *maxDepth = currentDepth; + } + calculateMaxTreeDepth(child, @(currentDepth.integerValue + 1), maxDepth); + } +} + @interface XCUIApplicationHelperTests : FBIntegrationTestCase @end @@ -40,7 +57,11 @@ - (void)testQueringSpringboard - (void)testApplicationTree { - XCTAssertNotNil(self.testedApplication.fb_tree); + NSDictionary *tree = self.testedApplication.fb_tree; + XCTAssertNotNil(tree); + NSNumber *maxDepth; + calculateMaxTreeDepth(tree, @0, &maxDepth); + XCTAssertGreaterThan(maxDepth.integerValue, 3); XCTAssertNotNil(self.testedApplication.fb_accessibilityTree); } From fbe1e3745ca19a2282c8f17868feabd4b2a8284c Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 2 Apr 2025 05:47:14 +0000 Subject: [PATCH 059/219] chore(release): 9.4.0 [skip ci] ## [9.4.0](https://github.com/appium/WebDriverAgent/compare/v9.3.3...v9.4.0) (2025-04-02) ### Features * Always apply the native snapshotting strategy for XCUIApplication instances ([#998](https://github.com/appium/WebDriverAgent/issues/998)) ([60f5aef](https://github.com/appium/WebDriverAgent/commit/60f5aeffdda85faffd60aba416dc9d92987f19ac)) --- CHANGELOG.md | 6 ++++++ WebDriverAgentLib/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6c43dec8..77ee27af5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [9.4.0](https://github.com/appium/WebDriverAgent/compare/v9.3.3...v9.4.0) (2025-04-02) + +### Features + +* Always apply the native snapshotting strategy for XCUIApplication instances ([#998](https://github.com/appium/WebDriverAgent/issues/998)) ([60f5aef](https://github.com/appium/WebDriverAgent/commit/60f5aeffdda85faffd60aba416dc9d92987f19ac)) + ## [9.3.3](https://github.com/appium/WebDriverAgent/compare/v9.3.2...v9.3.3) (2025-03-27) ### Bug Fixes diff --git a/WebDriverAgentLib/Info.plist b/WebDriverAgentLib/Info.plist index ee71d3bf5..be415d865 100644 --- a/WebDriverAgentLib/Info.plist +++ b/WebDriverAgentLib/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 9.3.3 + 9.4.0 CFBundleSignature ???? CFBundleVersion - 9.3.3 + 9.4.0 NSPrincipalClass diff --git a/package.json b/package.json index e0d86fe30..2f902be24 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "appium-webdriveragent", - "version": "9.3.3", + "version": "9.4.0", "description": "Package bundling WebDriverAgent", "main": "./build/index.js", "types": "./build/index.d.ts", From 445741d03313019016d4232f49e656d50f673f16 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Sat, 5 Apr 2025 18:00:31 +0900 Subject: [PATCH 060/219] chore: bump appium-ios-simulator --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2f902be24..9ae481c96 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "@appium/strongbox": "^0.x", "@appium/support": "^6.0.0", "appium-ios-device": "^2.7.25", - "appium-ios-simulator": "^6.0.0", + "appium-ios-simulator": "^6.2.2", "async-lock": "^1.0.0", "asyncbox": "^3.0.0", "axios": "^1.4.0", From 37af2edc17b7765867aef66cbfdb2bd2eb39d79c Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 5 Apr 2025 09:04:42 +0000 Subject: [PATCH 061/219] chore(release): 9.4.1 [skip ci] ## [9.4.1](https://github.com/appium/WebDriverAgent/compare/v9.4.0...v9.4.1) (2025-04-05) ### Miscellaneous Chores * bump appium-ios-simulator ([445741d](https://github.com/appium/WebDriverAgent/commit/445741d03313019016d4232f49e656d50f673f16)) --- CHANGELOG.md | 6 ++++++ WebDriverAgentLib/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 77ee27af5..6cb85ea72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [9.4.1](https://github.com/appium/WebDriverAgent/compare/v9.4.0...v9.4.1) (2025-04-05) + +### Miscellaneous Chores + +* bump appium-ios-simulator ([445741d](https://github.com/appium/WebDriverAgent/commit/445741d03313019016d4232f49e656d50f673f16)) + ## [9.4.0](https://github.com/appium/WebDriverAgent/compare/v9.3.3...v9.4.0) (2025-04-02) ### Features diff --git a/WebDriverAgentLib/Info.plist b/WebDriverAgentLib/Info.plist index be415d865..9c4dcda35 100644 --- a/WebDriverAgentLib/Info.plist +++ b/WebDriverAgentLib/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 9.4.0 + 9.4.1 CFBundleSignature ???? CFBundleVersion - 9.4.0 + 9.4.1 NSPrincipalClass diff --git a/package.json b/package.json index 9ae481c96..8eb150709 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "appium-webdriveragent", - "version": "9.4.0", + "version": "9.4.1", "description": "Package bundling WebDriverAgent", "main": "./build/index.js", "types": "./build/index.d.ts", From 85962aa374bbe0b46a4d42a715a1605cfcb61ad3 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Mon, 7 Apr 2025 19:42:13 +0900 Subject: [PATCH 062/219] ci: run on all Node LTS versions instead of only active (#1000) --- .github/workflows/unit-test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index b23ecbee6..6ff82176d 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -7,9 +7,9 @@ jobs: prepare_matrix: runs-on: ubuntu-latest outputs: - versions: ${{ steps.generate-matrix.outputs.active }} + versions: ${{ steps.generate-matrix.outputs.lts }} steps: - - name: Select all active LTS versions of Node.js + - name: Select all current LTS versions of Node.js id: generate-matrix uses: msimerson/node-lts-versions@v1 From fd31b9589199d0a7bc76919f6aa7c7c74c498b90 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Thu, 10 Apr 2025 08:04:29 +0200 Subject: [PATCH 063/219] feat: Add support for the autoClickAlertSelector setting (#1002) --- .../Categories/XCUIElement+FBClassChain.h | 3 +- .../Commands/FBSessionCommands.m | 29 +++++++++++ WebDriverAgentLib/Routing/FBCommandStatus.h | 2 +- WebDriverAgentLib/Routing/FBCommandStatus.m | 5 ++ WebDriverAgentLib/Routing/FBSession.h | 16 ++++++ WebDriverAgentLib/Routing/FBSession.m | 49 ++++++++++++++++--- WebDriverAgentLib/Utilities/FBConfiguration.h | 6 +++ WebDriverAgentLib/Utilities/FBConfiguration.m | 12 +++++ WebDriverAgentLib/Utilities/FBSettings.h | 1 + WebDriverAgentLib/Utilities/FBSettings.m | 1 + 10 files changed, 115 insertions(+), 9 deletions(-) diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBClassChain.h b/WebDriverAgentLib/Categories/XCUIElement+FBClassChain.h index 1cd1e8b93..b6e9ab924 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBClassChain.h +++ b/WebDriverAgentLib/Categories/XCUIElement+FBClassChain.h @@ -50,7 +50,8 @@ NS_ASSUME_NONNULL_BEGIN @return an array of descendants matching given class chain @throws FBUnknownAttributeException if any of predicates in the chain contains unknown attribute(s) */ -- (NSArray *)fb_descendantsMatchingClassChain:(NSString *)classChainQuery shouldReturnAfterFirstMatch:(BOOL)shouldReturnAfterFirstMatch; +- (NSArray *)fb_descendantsMatchingClassChain:(NSString *)classChainQuery + shouldReturnAfterFirstMatch:(BOOL)shouldReturnAfterFirstMatch; @end diff --git a/WebDriverAgentLib/Commands/FBSessionCommands.m b/WebDriverAgentLib/Commands/FBSessionCommands.m index 67b6b81e9..01409ab02 100644 --- a/WebDriverAgentLib/Commands/FBSessionCommands.m +++ b/WebDriverAgentLib/Commands/FBSessionCommands.m @@ -10,6 +10,7 @@ #import "FBSessionCommands.h" #import "FBCapabilities.h" +#import "FBClassChainQueryParser.h" #import "FBConfiguration.h" #import "FBExceptions.h" #import "FBLogger.h" @@ -347,6 +348,7 @@ + (NSArray *)routes FB_SETTING_INCLUDE_NON_MODAL_ELEMENTS: @([FBConfiguration includeNonModalElements]), FB_SETTING_ACCEPT_ALERT_BUTTON_SELECTOR: FBConfiguration.acceptAlertButtonSelector, FB_SETTING_DISMISS_ALERT_BUTTON_SELECTOR: FBConfiguration.dismissAlertButtonSelector, + FB_SETTING_AUTO_CLICK_ALERT_SELECTOR: FBConfiguration.autoClickAlertSelector, FB_SETTING_DEFAULT_ALERT_ACTION: request.session.defaultAlertAction ?: @"", FB_SETTING_MAX_TYPING_FREQUENCY: @([FBConfiguration maxTypingFrequency]), FB_SETTING_RESPECT_SYSTEM_ALERTS: @([FBConfiguration shouldRespectSystemAlerts]), @@ -431,6 +433,13 @@ + (NSArray *)routes if (nil != [settings objectForKey:FB_SETTING_DISMISS_ALERT_BUTTON_SELECTOR]) { [FBConfiguration setDismissAlertButtonSelector:(NSString *)[settings objectForKey:FB_SETTING_DISMISS_ALERT_BUTTON_SELECTOR]]; } + if (nil != [settings objectForKey:FB_SETTING_AUTO_CLICK_ALERT_SELECTOR]) { + FBCommandStatus *status = [self.class configureAutoClickAlertWithSelector:settings[FB_SETTING_AUTO_CLICK_ALERT_SELECTOR] + forSession:request.session]; + if (status.hasError) { + return FBResponseWithStatus(status); + } + } if (nil != [settings objectForKey:FB_SETTING_WAIT_FOR_IDLE_TIMEOUT]) { [FBConfiguration setWaitForIdleTimeout:[[settings objectForKey:FB_SETTING_WAIT_FOR_IDLE_TIMEOUT] doubleValue]]; } @@ -467,6 +476,26 @@ + (NSArray *)routes #pragma mark - Helpers ++ (FBCommandStatus *)configureAutoClickAlertWithSelector:(NSString *)selector + forSession:(FBSession *)session +{ + if (0 == [selector length]) { + [FBConfiguration setAutoClickAlertSelector:selector]; + [session disableAlertsMonitor]; + return [FBCommandStatus ok]; + } + + NSError *error; + FBClassChain *parsedChain = [FBClassChainQueryParser parseQuery:selector error:&error]; + if (nil == parsedChain) { + return [FBCommandStatus invalidSelectorErrorWithMessage:error.localizedDescription + traceback:nil]; + } + [FBConfiguration setAutoClickAlertSelector:selector]; + [session enableAlertsMonitor]; + return [FBCommandStatus ok]; +} + + (NSString *)buildTimestamp { return [NSString stringWithFormat:@"%@ %@", diff --git a/WebDriverAgentLib/Routing/FBCommandStatus.h b/WebDriverAgentLib/Routing/FBCommandStatus.h index 82bee1f60..7d61f68aa 100644 --- a/WebDriverAgentLib/Routing/FBCommandStatus.h +++ b/WebDriverAgentLib/Routing/FBCommandStatus.h @@ -19,7 +19,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, nullable, readonly) NSString* message; @property (nonatomic, nullable, readonly) NSString* traceback; @property (nonatomic, readonly) HTTPStatusCode statusCode; - +@property (nonatomic, readonly) BOOL hasError; + (instancetype)ok; diff --git a/WebDriverAgentLib/Routing/FBCommandStatus.m b/WebDriverAgentLib/Routing/FBCommandStatus.m index 453fb6192..4d1d9c589 100644 --- a/WebDriverAgentLib/Routing/FBCommandStatus.m +++ b/WebDriverAgentLib/Routing/FBCommandStatus.m @@ -109,6 +109,11 @@ - (instancetype)initWithError:(NSString *)error return self; } +- (BOOL)hasError +{ + return self.statusCode != kHTTPStatusCodeOK; +} + + (instancetype)ok { return [[FBCommandStatus alloc] initWithValue:nil]; diff --git a/WebDriverAgentLib/Routing/FBSession.h b/WebDriverAgentLib/Routing/FBSession.h index b617ae096..ca5be963d 100644 --- a/WebDriverAgentLib/Routing/FBSession.h +++ b/WebDriverAgentLib/Routing/FBSession.h @@ -121,6 +121,22 @@ extern NSString* const FB_SAFARI_BUNDLE_ID; */ - (NSUInteger)applicationStateWithBundleId:(NSString *)bundleIdentifier; +/** + Allows to enable automated session alerts monitoring. + Repeated calls are ignored if alerts monitoring has been already enabled. + + @returns YES if the actual alerts monitoring state has been changed + */ +- (BOOL)enableAlertsMonitor; + +/** + Allows to disable automated alerts monitoring + Repeated calls are ignored if alerts monitoring has been already disabled. + + @returns YES if the actual alerts monitoring state has been changed + */ +- (BOOL)disableAlertsMonitor; + @end NS_ASSUME_NONNULL_END diff --git a/WebDriverAgentLib/Routing/FBSession.m b/WebDriverAgentLib/Routing/FBSession.m index e8fb95a18..06afa5157 100644 --- a/WebDriverAgentLib/Routing/FBSession.m +++ b/WebDriverAgentLib/Routing/FBSession.m @@ -25,6 +25,7 @@ #import "FBXCTestDaemonsProxy.h" #import "XCUIApplication+FBQuiescence.h" #import "XCUIElement.h" +#import "XCUIElement+FBClassChain.h" /*! The intial value for the default application property. @@ -53,6 +54,22 @@ @implementation FBSession (FBAlertsMonitorDelegate) - (void)didDetectAlert:(FBAlert *)alert { + NSString *autoClickAlertSelector = FBConfiguration.autoClickAlertSelector; + if ([autoClickAlertSelector length] > 0) { + @try { + NSArray *matches = [alert.alertElement fb_descendantsMatchingClassChain:autoClickAlertSelector + shouldReturnAfterFirstMatch:YES]; + if (matches.count > 0) { + [[matches objectAtIndex:0] tap]; + } + } @catch (NSException *e) { + [FBLogger logFmt:@"Could not click at the alert element '%@'. Original error: %@", + autoClickAlertSelector, e.description]; + } + // This setting has priority over other settings if enabled + return; + } + if (nil == self.defaultAlertAction || 0 == self.defaultAlertAction.length) { return; } @@ -125,23 +142,41 @@ + (instancetype)initWithApplication:(nullable XCUIApplication *)application defaultAlertAction:(NSString *)defaultAlertAction { FBSession *session = [self.class initWithApplication:application]; - session.alertsMonitor = [[FBAlertsMonitor alloc] init]; - session.alertsMonitor.delegate = (id)session; session.defaultAlertAction = [defaultAlertAction lowercaseString]; - [session.alertsMonitor enable]; + [session enableAlertsMonitor]; return session; } +- (BOOL)enableAlertsMonitor +{ + if (nil != self.alertsMonitor) { + return NO; + } + + self.alertsMonitor = [[FBAlertsMonitor alloc] init]; + self.alertsMonitor.delegate = (id)self; + [self.alertsMonitor enable]; + return YES; +} + +- (BOOL)disableAlertsMonitor +{ + if (nil == self.alertsMonitor) { + return NO; + } + + [self.alertsMonitor disable]; + self.alertsMonitor = nil; + return YES; +} + - (void)kill { if (nil == _activeSession) { return; } - if (nil != self.alertsMonitor) { - [self.alertsMonitor disable]; - self.alertsMonitor = nil; - } + [self disableAlertsMonitor]; FBScreenRecordingPromise *activeScreenRecording = FBScreenRecordingContainer.sharedInstance.screenRecordingPromise; if (nil != activeScreenRecording) { diff --git a/WebDriverAgentLib/Utilities/FBConfiguration.h b/WebDriverAgentLib/Utilities/FBConfiguration.h index cb0a67dcf..f2da06736 100644 --- a/WebDriverAgentLib/Utilities/FBConfiguration.h +++ b/WebDriverAgentLib/Utilities/FBConfiguration.h @@ -283,6 +283,12 @@ typedef NS_ENUM(NSInteger, FBConfigurationKeyboardPreference) { + (void)setDismissAlertButtonSelector:(NSString *)classChainSelector; + (NSString *)dismissAlertButtonSelector; +/** + Sets class chain selector to apply for an automated alert click + */ ++ (void)setAutoClickAlertSelector:(NSString *)classChainSelector; ++ (NSString *)autoClickAlertSelector; + /** * Whether to use HIDEvent for text clear. * By default this is enabled and HIDEvent is used for text clear. diff --git a/WebDriverAgentLib/Utilities/FBConfiguration.m b/WebDriverAgentLib/Utilities/FBConfiguration.m index f3cf8e42f..7b75bcd9a 100644 --- a/WebDriverAgentLib/Utilities/FBConfiguration.m +++ b/WebDriverAgentLib/Utilities/FBConfiguration.m @@ -51,6 +51,7 @@ static BOOL FBIncludeNonModalElements; static NSString *FBAcceptAlertButtonSelector; static NSString *FBDismissAlertButtonSelector; +static NSString *FBAutoClickAlertSelector; static NSTimeInterval FBWaitForIdleTimeout; static NSTimeInterval FBAnimationCoolOffTimeout; static BOOL FBShouldUseCompactResponses; @@ -429,6 +430,16 @@ + (NSString *)dismissAlertButtonSelector return FBDismissAlertButtonSelector; } ++ (void)setAutoClickAlertSelector:(NSString *)classChainSelector +{ + FBAutoClickAlertSelector = classChainSelector; +} + ++ (NSString *)autoClickAlertSelector +{ + return FBAutoClickAlertSelector; +} + + (void)setUseClearTextShortcut:(BOOL)enabled { FBUseClearTextShortcut = enabled; @@ -509,6 +520,7 @@ + (void)resetSessionSettings FBIncludeNonModalElements = NO; FBAcceptAlertButtonSelector = @""; FBDismissAlertButtonSelector = @""; + FBAutoClickAlertSelector = @""; FBWaitForIdleTimeout = 10.; FBAnimationCoolOffTimeout = 2.; // 50 should be enough for the majority of the cases. The performance is acceptable for values up to 100. diff --git a/WebDriverAgentLib/Utilities/FBSettings.h b/WebDriverAgentLib/Utilities/FBSettings.h index 7f6d57970..cc25fe50c 100644 --- a/WebDriverAgentLib/Utilities/FBSettings.h +++ b/WebDriverAgentLib/Utilities/FBSettings.h @@ -39,6 +39,7 @@ extern NSString* const FB_SETTING_MAX_TYPING_FREQUENCY; extern NSString* const FB_SETTING_RESPECT_SYSTEM_ALERTS; extern NSString* const FB_SETTING_USE_CLEAR_TEXT_SHORTCUT; extern NSString* const FB_SETTING_LIMIT_XPATH_CONTEXT_SCOPE; +extern NSString* const FB_SETTING_AUTO_CLICK_ALERT_SELECTOR; NS_ASSUME_NONNULL_END diff --git a/WebDriverAgentLib/Utilities/FBSettings.m b/WebDriverAgentLib/Utilities/FBSettings.m index d91e343ed..09badf744 100644 --- a/WebDriverAgentLib/Utilities/FBSettings.m +++ b/WebDriverAgentLib/Utilities/FBSettings.m @@ -35,3 +35,4 @@ NSString* const FB_SETTING_RESPECT_SYSTEM_ALERTS = @"respectSystemAlerts"; NSString* const FB_SETTING_USE_CLEAR_TEXT_SHORTCUT = @"useClearTextShortcut"; NSString* const FB_SETTING_LIMIT_XPATH_CONTEXT_SCOPE = @"limitXPathContextScope"; +NSString* const FB_SETTING_AUTO_CLICK_ALERT_SELECTOR = @"autoClickAlertSelector"; From e22fb9a6409f30d86ef97c6c2e468ddac7c73f58 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 10 Apr 2025 06:10:54 +0000 Subject: [PATCH 064/219] chore(release): 9.5.0 [skip ci] ## [9.5.0](https://github.com/appium/WebDriverAgent/compare/v9.4.1...v9.5.0) (2025-04-10) ### Features * Add support for the autoClickAlertSelector setting ([#1002](https://github.com/appium/WebDriverAgent/issues/1002)) ([fd31b95](https://github.com/appium/WebDriverAgent/commit/fd31b9589199d0a7bc76919f6aa7c7c74c498b90)) --- CHANGELOG.md | 6 ++++++ WebDriverAgentLib/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6cb85ea72..b3848005f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [9.5.0](https://github.com/appium/WebDriverAgent/compare/v9.4.1...v9.5.0) (2025-04-10) + +### Features + +* Add support for the autoClickAlertSelector setting ([#1002](https://github.com/appium/WebDriverAgent/issues/1002)) ([fd31b95](https://github.com/appium/WebDriverAgent/commit/fd31b9589199d0a7bc76919f6aa7c7c74c498b90)) + ## [9.4.1](https://github.com/appium/WebDriverAgent/compare/v9.4.0...v9.4.1) (2025-04-05) ### Miscellaneous Chores diff --git a/WebDriverAgentLib/Info.plist b/WebDriverAgentLib/Info.plist index 9c4dcda35..5cc707d9a 100644 --- a/WebDriverAgentLib/Info.plist +++ b/WebDriverAgentLib/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 9.4.1 + 9.5.0 CFBundleSignature ???? CFBundleVersion - 9.4.1 + 9.5.0 NSPrincipalClass diff --git a/package.json b/package.json index 8eb150709..5ba6ed9b5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "appium-webdriveragent", - "version": "9.4.1", + "version": "9.5.0", "description": "Package bundling WebDriverAgent", "main": "./build/index.js", "types": "./build/index.d.ts", From cfe052bb3adb3f3b24d0a34f386c60cf1516b308 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Thu, 10 Apr 2025 12:51:07 +0200 Subject: [PATCH 065/219] fix: Make sure we don't store element snapshot in the cache (#1001) --- WebDriverAgentLib/Commands/FBElementCommands.m | 1 + WebDriverAgentLib/Routing/FBResponsePayload.m | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/WebDriverAgentLib/Commands/FBElementCommands.m b/WebDriverAgentLib/Commands/FBElementCommands.m index adcfa6ed6..b9f3faeb1 100644 --- a/WebDriverAgentLib/Commands/FBElementCommands.m +++ b/WebDriverAgentLib/Commands/FBElementCommands.m @@ -269,6 +269,7 @@ + (NSArray *)routes NSString *focusedUUID = [elementCache storeElement:(useNativeCachingStrategy ? focusedElement : [focusedElement fb_stableInstanceWithUid:focusedElement.fb_uid])]; + focusedElement.lastSnapshot = nil; if (focusedUUID && [focusedUUID isEqualToString:(id)request.parameters[@"uuid"]]) { isFocused = YES; } diff --git a/WebDriverAgentLib/Routing/FBResponsePayload.m b/WebDriverAgentLib/Routing/FBResponsePayload.m index f17517633..e94abee03 100644 --- a/WebDriverAgentLib/Routing/FBResponsePayload.m +++ b/WebDriverAgentLib/Routing/FBResponsePayload.m @@ -55,7 +55,9 @@ id FBResponseWithCachedElement(XCUIElement *element, FBElementCache *elementCache, BOOL compact) { [elementCache storeElement:maybeStable(element)]; - return FBResponseWithStatus([FBCommandStatus okWithValue:FBDictionaryResponseWithElement(element, compact)]); + NSDictionary *response = FBDictionaryResponseWithElement(element, compact); + element.lastSnapshot = nil; + return FBResponseWithStatus([FBCommandStatus okWithValue:response]); } id FBResponseWithCachedElements(NSArray *elements, FBElementCache *elementCache, BOOL compact) @@ -64,6 +66,7 @@ for (XCUIElement *element in elements) { [elementCache storeElement:maybeStable(element)]; [elementsResponse addObject:FBDictionaryResponseWithElement(element, compact)]; + element.lastSnapshot = nil; } return FBResponseWithStatus([FBCommandStatus okWithValue:elementsResponse]); } From 4b256c1a90b105d8c5f8799b0d0b2370f89ebc52 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 10 Apr 2025 10:55:05 +0000 Subject: [PATCH 066/219] chore(release): 9.5.1 [skip ci] ## [9.5.1](https://github.com/appium/WebDriverAgent/compare/v9.5.0...v9.5.1) (2025-04-10) ### Bug Fixes * Make sure we don't store element snapshot in the cache ([#1001](https://github.com/appium/WebDriverAgent/issues/1001)) ([cfe052b](https://github.com/appium/WebDriverAgent/commit/cfe052bb3adb3f3b24d0a34f386c60cf1516b308)) --- CHANGELOG.md | 6 ++++++ WebDriverAgentLib/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3848005f..0513dbb2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [9.5.1](https://github.com/appium/WebDriverAgent/compare/v9.5.0...v9.5.1) (2025-04-10) + +### Bug Fixes + +* Make sure we don't store element snapshot in the cache ([#1001](https://github.com/appium/WebDriverAgent/issues/1001)) ([cfe052b](https://github.com/appium/WebDriverAgent/commit/cfe052bb3adb3f3b24d0a34f386c60cf1516b308)) + ## [9.5.0](https://github.com/appium/WebDriverAgent/compare/v9.4.1...v9.5.0) (2025-04-10) ### Features diff --git a/WebDriverAgentLib/Info.plist b/WebDriverAgentLib/Info.plist index 5cc707d9a..b8a53c683 100644 --- a/WebDriverAgentLib/Info.plist +++ b/WebDriverAgentLib/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 9.5.0 + 9.5.1 CFBundleSignature ???? CFBundleVersion - 9.5.0 + 9.5.1 NSPrincipalClass diff --git a/package.json b/package.json index 5ba6ed9b5..502b4bdbc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "appium-webdriveragent", - "version": "9.5.0", + "version": "9.5.1", "description": "Package bundling WebDriverAgent", "main": "./build/index.js", "types": "./build/index.d.ts", From 6603a0ba384917d39389509958ccac03ad174610 Mon Sep 17 00:00:00 2001 From: Kazuaki Matsuo Date: Sat, 19 Apr 2025 16:52:11 +0900 Subject: [PATCH 067/219] fix: Missing text in long text for get text/value (#1007) * replace long text test * add workaround * here too * add comments --- .../XCUIElement+FBWebDriverAttributes.m | 2 + .../Commands/FBElementCommands.m | 3 +- .../Resources/Base.lproj/Main.storyboard | 71 ++++++++++--------- .../FBElementAttributeTests.m | 2 +- 4 files changed, 44 insertions(+), 34 deletions(-) diff --git a/WebDriverAgentLib/Categories/XCUIElement+FBWebDriverAttributes.m b/WebDriverAgentLib/Categories/XCUIElement+FBWebDriverAttributes.m index 4efe2dde6..ac029d791 100644 --- a/WebDriverAgentLib/Categories/XCUIElement+FBWebDriverAttributes.m +++ b/WebDriverAgentLib/Categories/XCUIElement+FBWebDriverAttributes.m @@ -30,6 +30,8 @@ @implementation XCUIElement (WebDriverAttributesForwarding) { BOOL inDepth = [name isEqualToString:FBStringify(XCUIElement, isWDAccessible)] || [name isEqualToString:FBStringify(XCUIElement, isWDAccessibilityContainer)] + // To retrice entire text https://github.com/appium/appium-xcuitest-driver/issues/2552 + || [name isEqualToString:FBStringify(XCUIElement, wdValue)] || [name isEqualToString:FBStringify(XCUIElement, wdIndex)]; return [self fb_takeSnapshot:inDepth]; } diff --git a/WebDriverAgentLib/Commands/FBElementCommands.m b/WebDriverAgentLib/Commands/FBElementCommands.m index b9f3faeb1..67d5dbe5f 100644 --- a/WebDriverAgentLib/Commands/FBElementCommands.m +++ b/WebDriverAgentLib/Commands/FBElementCommands.m @@ -151,7 +151,8 @@ + (NSArray *)routes { FBElementCache *elementCache = request.session.elementCache; XCUIElement *element = [elementCache elementForUUID:(NSString *)request.parameters[@"uuid"]]; - FBXCElementSnapshotWrapper *wrappedSnapshot = [FBXCElementSnapshotWrapper ensureWrapped:[element fb_takeSnapshot:NO]]; + // 'fb_takeSnapshot:YES' is to retrice entire text https://github.com/appium/appium-xcuitest-driver/issues/2552 + FBXCElementSnapshotWrapper *wrappedSnapshot = [FBXCElementSnapshotWrapper ensureWrapped:[element fb_takeSnapshot:YES]]; id text = FBFirstNonEmptyValue(wrappedSnapshot.wdValue, wrappedSnapshot.wdLabel); return FBResponseWithObject(text ?: @""); } diff --git a/WebDriverAgentTests/IntegrationApp/Resources/Base.lproj/Main.storyboard b/WebDriverAgentTests/IntegrationApp/Resources/Base.lproj/Main.storyboard index db5221045..5fb805f28 100644 --- a/WebDriverAgentTests/IntegrationApp/Resources/Base.lproj/Main.storyboard +++ b/WebDriverAgentTests/IntegrationApp/Resources/Base.lproj/Main.storyboard @@ -1,9 +1,10 @@ - + - + + @@ -19,7 +20,7 @@ - - - - - - - - - - - + @@ -240,32 +240,32 @@ - + - + - + - + - + - + @@ -349,6 +349,9 @@ + + + @@ -367,7 +370,7 @@ - + @@ -377,7 +380,7 @@