appium-mac2-driver 3.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +27 -1
- package/WebDriverAgentMac/IntegrationTests/AMPasteboardTests.m +111 -0
- package/WebDriverAgentMac/IntegrationTests/AMW3CActionsTests.m +1 -1
- package/WebDriverAgentMac/WebDriverAgentLib/Categories/XCUIApplication+AMActiveElement.h +1 -1
- package/WebDriverAgentMac/WebDriverAgentLib/Categories/XCUIApplication+AMSource.h +2 -2
- package/WebDriverAgentMac/WebDriverAgentLib/Categories/XCUIApplication+FBW3CActions.h +1 -1
- package/WebDriverAgentMac/WebDriverAgentLib/Categories/XCUIElementQuery+AMHelpers.h +2 -2
- package/WebDriverAgentMac/WebDriverAgentLib/Commands/AMWindowCommands.m +3 -3
- package/WebDriverAgentMac/WebDriverAgentLib/Commands/FBCustomCommands.m +33 -0
- package/WebDriverAgentMac/WebDriverAgentLib/Routing/FBExceptions.h +3 -3
- package/WebDriverAgentMac/WebDriverAgentLib/Routing/FBResponseJSONPayload.h +1 -1
- package/WebDriverAgentMac/WebDriverAgentLib/Routing/FBScreenRecordingRequest.h +1 -1
- package/WebDriverAgentMac/WebDriverAgentLib/Routing/FBScreenRecordingRequest.m +2 -2
- package/WebDriverAgentMac/WebDriverAgentLib/Utilities/AMPasteboard.h +47 -0
- package/WebDriverAgentMac/WebDriverAgentLib/Utilities/AMPasteboard.m +128 -0
- package/WebDriverAgentMac/WebDriverAgentLib/Utilities/AMScreenUtils.h +1 -1
- package/WebDriverAgentMac/WebDriverAgentLib/Utilities/AMSettings.h +1 -1
- package/WebDriverAgentMac/WebDriverAgentLib/Utilities/AMSnapshotUtils.h +2 -2
- package/WebDriverAgentMac/WebDriverAgentLib/Utilities/FBBaseActionsSynthesizer.h +9 -9
- package/WebDriverAgentMac/WebDriverAgentLib/Utilities/FBClassChainQueryParser.h +4 -4
- package/WebDriverAgentMac/WebDriverAgentLib/Utilities/FBClassChainQueryParser.m +4 -4
- package/WebDriverAgentMac/WebDriverAgentLib/Utilities/FBElementUtils.h +2 -2
- package/WebDriverAgentMac/WebDriverAgentLib/Utilities/FBXPath.h +2 -2
- package/WebDriverAgentMac/WebDriverAgentLib/Utilities/FBXPath.m +2 -2
- package/WebDriverAgentMac/WebDriverAgentMac.xcodeproj/project.pbxproj +12 -0
- package/build/lib/commands/clipboard.d.ts +19 -0
- package/build/lib/commands/clipboard.d.ts.map +1 -0
- package/build/lib/commands/clipboard.js +31 -0
- package/build/lib/commands/clipboard.js.map +1 -0
- package/build/lib/commands/native-record-screen.js +4 -0
- package/build/lib/commands/native-record-screen.js.map +1 -1
- package/build/lib/doctor/optional-checks.js +2 -4
- package/build/lib/doctor/optional-checks.js.map +1 -1
- package/build/lib/doctor/required-checks.js +2 -4
- package/build/lib/doctor/required-checks.js.map +1 -1
- package/build/lib/driver.d.ts +24 -1
- package/build/lib/driver.d.ts.map +1 -1
- package/build/lib/driver.js +49 -33
- package/build/lib/driver.js.map +1 -1
- package/build/lib/execute-method-map.d.ts +13 -0
- package/build/lib/execute-method-map.d.ts.map +1 -1
- package/build/lib/execute-method-map.js +11 -0
- package/build/lib/execute-method-map.js.map +1 -1
- package/build/lib/wda-mac.js +6 -2
- package/build/lib/wda-mac.js.map +1 -1
- package/lib/commands/clipboard.ts +35 -0
- package/lib/driver.js +11 -0
- package/lib/execute-method-map.ts +11 -0
- package/lib/wda-mac.js +2 -2
- package/npm-shrinkwrap.json +121 -109
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [3.1.0](https://github.com/appium/appium-mac2-driver/compare/v3.0.1...v3.1.0) (2025-10-01)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* Add clipboard support ([#346](https://github.com/appium/appium-mac2-driver/issues/346)) ([a3652fd](https://github.com/appium/appium-mac2-driver/commit/a3652fd2e29c68a30f677200ad8a2dd9148898d8))
|
|
7
|
+
|
|
8
|
+
## [3.0.1](https://github.com/appium/appium-mac2-driver/compare/v3.0.0...v3.0.1) (2025-09-28)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Miscellaneous Chores
|
|
12
|
+
|
|
13
|
+
* fix typos ([#344](https://github.com/appium/appium-mac2-driver/issues/344)) ([3687efa](https://github.com/appium/appium-mac2-driver/commit/3687efa3b43c83e2ec2a3f1414c6fa3b7f7da5c0))
|
|
14
|
+
|
|
1
15
|
## [3.0.0](https://github.com/appium/appium-mac2-driver/compare/v2.2.2...v3.0.0) (2025-08-17)
|
|
2
16
|
|
|
3
17
|
|
package/README.md
CHANGED
|
@@ -83,7 +83,7 @@ Mac2 driver supports the following location strategies:
|
|
|
83
83
|
|
|
84
84
|
Name | Description | Speed Ranking | Pseudocode
|
|
85
85
|
--- | --- | --- | ---
|
|
86
|
-
accessibilityId, id, name | These all strategies are mapped to the same Mac2 driver ByIdentifier lookup strategy. The locator matches the passed value with element's `
|
|
86
|
+
accessibilityId, id, name | These all strategies are mapped to the same Mac2 driver ByIdentifier lookup strategy. The locator matches the passed value with element's `identifier` attribute case-sensitively. | `⭐⭐⭐⭐⭐` | AppiumBy.accessibilityId("identifier"), By.id("identifier"), By.name("identifier")
|
|
87
87
|
className | Class name uses stringified element types for lookup | `⭐⭐⭐⭐⭐` | By.className("XCUIElementTypePopUpButton")
|
|
88
88
|
predicate | Lookup by predicate is natively supported by XCTest and is as fast as previous lookup strategies. This lookup strategy could only use the supported [element attributes](#element-attributes). Unknown attribute names would throw an exception. Check [NSPredicate cheat sheet](https://academy.realm.io/posts/nspredicate-cheatsheet/) for more details on how to build effective and flexible locators. | `⭐⭐⭐⭐⭐` | AppiumBy.iOSNsPredicateString("elementType == 2 AND label BEGINSWITH 'Safari'")
|
|
89
89
|
classChain | This strategy is a combination of Xpath flexibility and fast predicate lookup. Prefer it over Xpath unless there is no other way to build the desired locator. Visit [Class Chain Construction Rules tutorial](https://github.com/facebookarchive/WebDriverAgent/wiki/Class-Chain-Queries-Construction-Rules) to get more knowledge on how to build class chain locators. | `⭐⭐⭐⭐` | AppiumBy.iOSClassChain("**/XCUIElementTypeRuler[$elementType == 72 AND value BEGINSWITH '10'$]")
|
|
@@ -702,6 +702,32 @@ Name | Type | Description | Example
|
|
|
702
702
|
id | number | Display identifier | 12345
|
|
703
703
|
isMain | boolean | Is `true` if the display is configured as a main system display | false
|
|
704
704
|
|
|
705
|
+
### macos: setClipboard
|
|
706
|
+
|
|
707
|
+
Set the macOS clipboard content as base64-encoded string. The existing clipboard content (if present) will be cleared.
|
|
708
|
+
|
|
709
|
+
#### Arguments
|
|
710
|
+
|
|
711
|
+
Name | Type | Required | Description | Example
|
|
712
|
+
--- | --- | --- | --- | ---
|
|
713
|
+
content | string | yes | The content to be set as base64 encoded string | hello
|
|
714
|
+
contentType | string | no | The type of the content to set. Only `plaintext` (default), `image` and `url` are supported. If set to `url`, then `content` must be a valid URL. If set to `image`, then `content` must contain a valid PNG or TIFF image payload. | url
|
|
715
|
+
|
|
716
|
+
### macos: getClipboard
|
|
717
|
+
|
|
718
|
+
Get the macOS clipboard content as base64-encoded string.
|
|
719
|
+
|
|
720
|
+
#### Arguments
|
|
721
|
+
|
|
722
|
+
Name | Type | Required | Description | Example
|
|
723
|
+
--- | --- | --- | --- | ---
|
|
724
|
+
contentType | string | no | The type of the content to get. Only `plaintext` (default), `image` and `url` are supported. | image
|
|
725
|
+
|
|
726
|
+
#### Returns
|
|
727
|
+
|
|
728
|
+
The actual clipboard content encoded into base64 string. An empty string is returned if the clipboard
|
|
729
|
+
contains no data for the given content type.
|
|
730
|
+
|
|
705
731
|
|
|
706
732
|
## Application Under Test Concept
|
|
707
733
|
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
* you may not use this file except in compliance with the License.
|
|
4
|
+
* See the NOTICE file distributed with this work for additional
|
|
5
|
+
* information regarding copyright ownership.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
#import <XCTest/XCTest.h>
|
|
18
|
+
|
|
19
|
+
#import "AMIntegrationTestCase.h"
|
|
20
|
+
#import "AMPasteboard.h"
|
|
21
|
+
|
|
22
|
+
@interface AMPasteboardTests : AMIntegrationTestCase
|
|
23
|
+
@end
|
|
24
|
+
|
|
25
|
+
NSData *dataFromImage(NSImage *image) {
|
|
26
|
+
if (!image) return nil;
|
|
27
|
+
|
|
28
|
+
NSSize size = [image size];
|
|
29
|
+
NSBitmapImageRep *bitmapRep = [[NSBitmapImageRep alloc]
|
|
30
|
+
initWithBitmapDataPlanes:NULL
|
|
31
|
+
pixelsWide:size.width
|
|
32
|
+
pixelsHigh:size.height
|
|
33
|
+
bitsPerSample:8
|
|
34
|
+
samplesPerPixel:4
|
|
35
|
+
hasAlpha:YES
|
|
36
|
+
isPlanar:NO
|
|
37
|
+
colorSpaceName:NSCalibratedRGBColorSpace
|
|
38
|
+
bytesPerRow:0
|
|
39
|
+
bitsPerPixel:0];
|
|
40
|
+
if (!bitmapRep) return nil;
|
|
41
|
+
|
|
42
|
+
NSGraphicsContext *context = [NSGraphicsContext graphicsContextWithBitmapImageRep:bitmapRep];
|
|
43
|
+
if (!context) return nil;
|
|
44
|
+
|
|
45
|
+
[NSGraphicsContext saveGraphicsState];
|
|
46
|
+
[NSGraphicsContext setCurrentContext:context];
|
|
47
|
+
[image drawInRect:NSMakeRect(0, 0, size.width, size.height)
|
|
48
|
+
fromRect:NSZeroRect
|
|
49
|
+
operation:NSCompositingOperationCopy
|
|
50
|
+
fraction:1.0];
|
|
51
|
+
[NSGraphicsContext restoreGraphicsState];
|
|
52
|
+
|
|
53
|
+
return [bitmapRep representationUsingType:NSBitmapImageFileTypePNG properties:@{}];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@implementation AMPasteboardTests
|
|
58
|
+
|
|
59
|
+
- (void)testPasteboardPlaintex
|
|
60
|
+
{
|
|
61
|
+
NSError *error;
|
|
62
|
+
NSString *expected = @"test";
|
|
63
|
+
XCTAssertTrue([AMPasteboard setData:[expected dataUsingEncoding:NSUTF8StringEncoding]
|
|
64
|
+
forType:@"plaintext"
|
|
65
|
+
error:&error]);
|
|
66
|
+
XCTAssertNil(error);
|
|
67
|
+
NSData *actual = [AMPasteboard dataForType:@"plaintext" error:&error];
|
|
68
|
+
XCTAssertNotNil(actual);
|
|
69
|
+
XCTAssertNil(error);
|
|
70
|
+
XCTAssertEqualObjects([[NSString alloc] initWithData:actual encoding:NSUTF8StringEncoding], expected);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
- (void)testPasteboardUrl
|
|
74
|
+
{
|
|
75
|
+
NSError *error;
|
|
76
|
+
NSString *expected = @"https://appium.io";
|
|
77
|
+
XCTAssertTrue([AMPasteboard setData:[expected dataUsingEncoding:NSUTF8StringEncoding]
|
|
78
|
+
forType:@"url"
|
|
79
|
+
error:&error]);
|
|
80
|
+
XCTAssertNil(error);
|
|
81
|
+
NSData *actual = [AMPasteboard dataForType:@"url" error:&error];
|
|
82
|
+
XCTAssertNotNil(actual);
|
|
83
|
+
XCTAssertNil(error);
|
|
84
|
+
XCTAssertEqualObjects([[NSString alloc] initWithData:actual encoding:NSUTF8StringEncoding], expected);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
- (void)testPasteboardImage
|
|
88
|
+
{
|
|
89
|
+
NSImage *image = [[NSImage alloc] initWithSize:NSMakeSize(1, 1)];
|
|
90
|
+
[image lockFocus];
|
|
91
|
+
[[NSColor clearColor] setFill];
|
|
92
|
+
NSRectFill(NSMakeRect(0, 0, 1, 1));
|
|
93
|
+
[image unlockFocus];
|
|
94
|
+
|
|
95
|
+
NSData *expected = dataFromImage(image);
|
|
96
|
+
if (nil == expected) {
|
|
97
|
+
XCTFail(@"imageData cannot be nil");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
NSError *error;
|
|
101
|
+
XCTAssertTrue([AMPasteboard setData:expected
|
|
102
|
+
forType:@"image"
|
|
103
|
+
error:&error]);
|
|
104
|
+
XCTAssertNil(error);
|
|
105
|
+
NSData *actual = [AMPasteboard dataForType:@"image" error:&error];
|
|
106
|
+
XCTAssertNotNil(actual);
|
|
107
|
+
XCTAssertNil(error);
|
|
108
|
+
XCTAssertEqualObjects(actual, expected);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
@end
|
|
@@ -21,7 +21,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
21
21
|
@interface XCUIApplication (AMActiveElement)
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
|
-
|
|
24
|
+
Retrieves the element, which holds the keyboard input focus
|
|
25
25
|
*/
|
|
26
26
|
- (nullable XCUIElement *)am_activeElement;
|
|
27
27
|
|
|
@@ -21,12 +21,12 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
21
21
|
@interface XCUIApplication (AMSource)
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
|
-
|
|
24
|
+
Retrieves XML application source representation
|
|
25
25
|
*/
|
|
26
26
|
- (NSString *)am_xmlRepresentation;
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
|
-
|
|
29
|
+
Retrieves description application source representation.
|
|
30
30
|
Actually, the value of debugDescription property
|
|
31
31
|
*/
|
|
32
32
|
- (NSString *)am_descriptionRepresentation;
|
|
@@ -19,7 +19,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
19
19
|
Perform complex touch action in scope of the current application.
|
|
20
20
|
|
|
21
21
|
@param actions Array of dictionaries, whose format is described in W3C spec (https://github.com/jlipps/simple-wd-spec#perform-actions)
|
|
22
|
-
@param elementCache Cached elements mapping for the
|
|
22
|
+
@param elementCache Cached elements mapping for the current application. The method assumes all elements are already represented by their actual instances if nil value is set
|
|
23
23
|
@param error If there is an error, upon return contains an NSError object that describes the problem
|
|
24
24
|
@return YES If the touch action has been successfully performed without errors
|
|
25
25
|
*/
|
|
@@ -23,14 +23,14 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
23
23
|
/**
|
|
24
24
|
Retrieves the first match from the query
|
|
25
25
|
|
|
26
|
-
@returns Matched element instance
|
|
26
|
+
@returns Matched element instance or nil if no element is found
|
|
27
27
|
*/
|
|
28
28
|
- (nullable XCUIElement *)am_firstMatch;
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
31
|
Retrieves all matches from the query
|
|
32
32
|
|
|
33
|
-
@returns Matched element instances
|
|
33
|
+
@returns Matched element instances or an empty array if no matches are found
|
|
34
34
|
*/
|
|
35
35
|
- (NSArray<XCUIElement *> *)am_allMatches;
|
|
36
36
|
|
|
@@ -32,21 +32,21 @@
|
|
|
32
32
|
{
|
|
33
33
|
return [self performClickWithButtonId:@"_XCUI:FullScreenWindow"
|
|
34
34
|
request:request
|
|
35
|
-
errorMessage:[NSString stringWithFormat:@"%@ window cannot be maximized because the
|
|
35
|
+
errorMessage:[NSString stringWithFormat:@"%@ window cannot be maximized because the corresponding button is not available", request.session.currentApplication.description]];
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
+ (id<FBResponsePayload>)handleFullscreenWindow:(FBRouteRequest *)request
|
|
39
39
|
{
|
|
40
40
|
return [self performClickWithButtonId:@"_XCUI:FullScreenWindow"
|
|
41
41
|
request:request
|
|
42
|
-
errorMessage:[NSString stringWithFormat:@"%@ window cannot be put into fullscreen mode because the
|
|
42
|
+
errorMessage:[NSString stringWithFormat:@"%@ window cannot be put into fullscreen mode because the corresponding button is not available", request.session.currentApplication.description]];
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
+ (id<FBResponsePayload>)handleMinimizeWindow:(FBRouteRequest *)request
|
|
46
46
|
{
|
|
47
47
|
return [self performClickWithButtonId:@"_XCUI:MinimizeWindow"
|
|
48
48
|
request:request
|
|
49
|
-
errorMessage:[NSString stringWithFormat:@"%@ window cannot be minimized because the
|
|
49
|
+
errorMessage:[NSString stringWithFormat:@"%@ window cannot be minimized because the corresponding button is not available", request.session.currentApplication.description]];
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
+ (id<FBResponsePayload>)performClickWithButtonId:(NSString *)buttonId
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
#import "FBCustomCommands.h"
|
|
11
11
|
|
|
12
|
+
#import "AMPasteboard.h"
|
|
12
13
|
#import "FBResponsePayload.h"
|
|
13
14
|
#import "FBRoute.h"
|
|
14
15
|
#import "FBRouteRequest.h"
|
|
@@ -21,6 +22,10 @@
|
|
|
21
22
|
return
|
|
22
23
|
@[
|
|
23
24
|
[[FBRoute POST:@"/timeouts"] respondWithTarget:self action:@selector(handleTimeouts:)],
|
|
25
|
+
[[FBRoute POST:@"/wda/setPasteboard"] respondWithTarget:self action:@selector(handleSetPasteboard:)],
|
|
26
|
+
[[FBRoute POST:@"/wda/setPasteboard"].withoutSession respondWithTarget:self action:@selector(handleSetPasteboard:)],
|
|
27
|
+
[[FBRoute POST:@"/wda/getPasteboard"] respondWithTarget:self action:@selector(handleGetPasteboard:)],
|
|
28
|
+
[[FBRoute POST:@"/wda/getPasteboard"].withoutSession respondWithTarget:self action:@selector(handleGetPasteboard:)],
|
|
24
29
|
[[FBRoute OPTIONS:@"/*"].withoutSession respondWithTarget:self action:@selector(handlePingCommand:)],
|
|
25
30
|
];
|
|
26
31
|
}
|
|
@@ -34,6 +39,34 @@
|
|
|
34
39
|
return FBResponseWithOK();
|
|
35
40
|
}
|
|
36
41
|
|
|
42
|
+
+ (id<FBResponsePayload>)handleSetPasteboard:(FBRouteRequest *)request
|
|
43
|
+
{
|
|
44
|
+
NSString *contentType = request.arguments[@"contentType"] ?: @"plaintext";
|
|
45
|
+
NSData *content = [[NSData alloc] initWithBase64EncodedString:(NSString *)request.arguments[@"content"]
|
|
46
|
+
options:NSDataBase64DecodingIgnoreUnknownCharacters];
|
|
47
|
+
if (nil == content) {
|
|
48
|
+
return FBResponseWithStatus([FBCommandStatus
|
|
49
|
+
invalidArgumentErrorWithMessage:@"Cannot decode the pasteboard content from base64"
|
|
50
|
+
traceback:nil]);
|
|
51
|
+
}
|
|
52
|
+
NSError *error;
|
|
53
|
+
if (![AMPasteboard setData:content forType:contentType error:&error]) {
|
|
54
|
+
return FBResponseWithUnknownError(error);
|
|
55
|
+
}
|
|
56
|
+
return FBResponseWithOK();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
+ (id<FBResponsePayload>)handleGetPasteboard:(FBRouteRequest *)request
|
|
60
|
+
{
|
|
61
|
+
NSString *contentType = request.arguments[@"contentType"] ?: @"plaintext";
|
|
62
|
+
NSError *error;
|
|
63
|
+
id result = [AMPasteboard dataForType:contentType error:&error];
|
|
64
|
+
if (nil == result) {
|
|
65
|
+
return FBResponseWithUnknownError(error);
|
|
66
|
+
}
|
|
67
|
+
return FBResponseWithObject([result base64EncodedStringWithOptions:0]);
|
|
68
|
+
}
|
|
69
|
+
|
|
37
70
|
+ (id<FBResponsePayload>)handlePingCommand:(FBRouteRequest *)request
|
|
38
71
|
{
|
|
39
72
|
return FBResponseWithOK();
|
|
@@ -30,16 +30,16 @@ extern NSString *const FBElementNotVisibleException;
|
|
|
30
30
|
extern NSString *const FBTimeoutException;
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
|
-
The exception
|
|
33
|
+
The exception happens if the cached element does not exist in DOM anymore
|
|
34
34
|
*/
|
|
35
35
|
extern NSString *const FBStaleElementException;
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
-
The exception
|
|
38
|
+
The exception happens if the provided XPath expression cannot be compiled because of a syntax error
|
|
39
39
|
*/
|
|
40
40
|
extern NSString *const FBInvalidXPathException;
|
|
41
41
|
/**
|
|
42
|
-
The exception
|
|
42
|
+
The exception happens if any internal error is triggered during XPath matching procedure
|
|
43
43
|
*/
|
|
44
44
|
extern NSString *const FBXPathQueryEvaluationException;
|
|
45
45
|
|
|
@@ -20,7 +20,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
20
20
|
@property (readonly, nonatomic, nullable) NSNumber *displayID;
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
|
-
Creates a custom wrapper for a screen recording
|
|
23
|
+
Creates a custom wrapper for a screen recording request
|
|
24
24
|
|
|
25
25
|
@param fps FPS value, see baove
|
|
26
26
|
@param codec Codex value, see above
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
SEL videoEncodingConstructorSelector = NSSelectorFromString(@"initWithCodec:frameRate:");
|
|
38
38
|
if (![videoEncodingAllocated respondsToSelector:videoEncodingConstructorSelector]) {
|
|
39
39
|
[[[FBErrorBuilder builder]
|
|
40
|
-
withDescription:@"'initWithCodec:frameRate:'
|
|
40
|
+
withDescription:@"'initWithCodec:frameRate:' constructor is not found on XCTVideoEncoding class"]
|
|
41
41
|
buildError:error];
|
|
42
42
|
return nil;
|
|
43
43
|
}
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
SEL screenRecordingRequestConstructorSelector = NSSelectorFromString(@"initWithScreenID:rect:preferredEncoding:");
|
|
70
70
|
if (![screenRecordingRequestAllocated respondsToSelector:screenRecordingRequestConstructorSelector]) {
|
|
71
71
|
[[[FBErrorBuilder builder]
|
|
72
|
-
withDescription:@"'initWithScreenID:rect:preferredEncoding:'
|
|
72
|
+
withDescription:@"'initWithScreenID:rect:preferredEncoding:' constructor is not found on XCTScreenRecordingRequest class"]
|
|
73
73
|
buildError:error];
|
|
74
74
|
return nil;
|
|
75
75
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
* you may not use this file except in compliance with the License.
|
|
4
|
+
* See the NOTICE file distributed with this work for additional
|
|
5
|
+
* information regarding copyright ownership.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
#import <XCTest/XCTest.h>
|
|
19
|
+
|
|
20
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
21
|
+
|
|
22
|
+
@interface AMPasteboard : NSObject
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
Sets data to the general pasteboard
|
|
26
|
+
|
|
27
|
+
@param data base64-encoded string containing the data chunk which is going to be written to the pasteboard
|
|
28
|
+
@param type one of the possible data types to set: plaintext, url, image
|
|
29
|
+
@param error If there is an error, upon return contains an NSError object that describes the problem
|
|
30
|
+
@return YES if the operation was successful
|
|
31
|
+
*/
|
|
32
|
+
+ (BOOL)setData:(NSData *)data forType:(NSString *)type error:(NSError **)error;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
Gets the data contained in the general pasteboard
|
|
36
|
+
|
|
37
|
+
@param type one of the possible data types to get: plaintext, url, image
|
|
38
|
+
@param error If there is an error, upon return contains an NSError object that describes the problem
|
|
39
|
+
@return NSData object, containing the pasteboard content or an empty string if the pasteboard is empty.
|
|
40
|
+
nil is returned if there was an error while getting the data from the pasteboard
|
|
41
|
+
*/
|
|
42
|
+
+ (nullable NSData *)dataForType:(NSString *)type error:(NSError **)error;
|
|
43
|
+
|
|
44
|
+
@end
|
|
45
|
+
|
|
46
|
+
NS_ASSUME_NONNULL_END
|
|
47
|
+
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
* you may not use this file except in compliance with the License.
|
|
4
|
+
* See the NOTICE file distributed with this work for additional
|
|
5
|
+
* information regarding copyright ownership.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
#import "AMPasteboard.h"
|
|
19
|
+
|
|
20
|
+
#import <mach/mach_time.h>
|
|
21
|
+
#import "FBErrorBuilder.h"
|
|
22
|
+
#import "FBMacros.h"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@implementation AMPasteboard
|
|
26
|
+
|
|
27
|
+
+ (BOOL)setData:(NSData *)data forType:(NSString *)type error:(NSError **)error
|
|
28
|
+
{
|
|
29
|
+
NSPasteboard *pb = NSPasteboard.generalPasteboard;
|
|
30
|
+
if ([type.lowercaseString isEqualToString:@"plaintext"]) {
|
|
31
|
+
[pb clearContents];
|
|
32
|
+
if (![pb setString:[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]
|
|
33
|
+
forType:NSPasteboardTypeString]) {
|
|
34
|
+
NSString *description = @"Failed to copy string to the clipboard";
|
|
35
|
+
if (error) {
|
|
36
|
+
*error = [[FBErrorBuilder.builder withDescription:description] build];
|
|
37
|
+
}
|
|
38
|
+
return NO;
|
|
39
|
+
}
|
|
40
|
+
} else if ([type.lowercaseString isEqualToString:@"image"]) {
|
|
41
|
+
NSImage *image = [[NSImage alloc] initWithData:data];
|
|
42
|
+
if (nil == image) {
|
|
43
|
+
NSString *description = @"No image can be parsed from the given pasteboard data";
|
|
44
|
+
if (error) {
|
|
45
|
+
*error = [[FBErrorBuilder.builder withDescription:description] build];
|
|
46
|
+
}
|
|
47
|
+
return NO;
|
|
48
|
+
}
|
|
49
|
+
[pb clearContents];
|
|
50
|
+
if (![pb writeObjects:@[image]]) {
|
|
51
|
+
NSString *description = @"Failed to copy image to the clipboard";
|
|
52
|
+
if (error) {
|
|
53
|
+
*error = [[FBErrorBuilder.builder withDescription:description] build];
|
|
54
|
+
}
|
|
55
|
+
return NO;
|
|
56
|
+
}
|
|
57
|
+
} else if ([type.lowercaseString isEqualToString:@"url"]) {
|
|
58
|
+
NSString *urlString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
|
59
|
+
NSURL *url = [[NSURL alloc] initWithString:urlString];
|
|
60
|
+
if (nil == url) {
|
|
61
|
+
NSString *description = @"No URL can be parsed from the given data";
|
|
62
|
+
if (error) {
|
|
63
|
+
*error = [[FBErrorBuilder.builder withDescription:description] build];
|
|
64
|
+
}
|
|
65
|
+
return NO;
|
|
66
|
+
}
|
|
67
|
+
[pb clearContents];
|
|
68
|
+
if (![pb setString:[url absoluteString] forType:NSPasteboardTypeURL]) {
|
|
69
|
+
NSString *description = @"Failed to copy URL to the clipboard";
|
|
70
|
+
if (error) {
|
|
71
|
+
*error = [[FBErrorBuilder.builder withDescription:description] build];
|
|
72
|
+
}
|
|
73
|
+
return NO;
|
|
74
|
+
}
|
|
75
|
+
} else {
|
|
76
|
+
NSString *description = [NSString stringWithFormat:@"Unsupported content type: %@", type];
|
|
77
|
+
if (error) {
|
|
78
|
+
*error = [[FBErrorBuilder.builder withDescription:description] build];
|
|
79
|
+
}
|
|
80
|
+
return NO;
|
|
81
|
+
}
|
|
82
|
+
return YES;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
+ (NSData *)dataForType:(NSString *)type error:(NSError **)error
|
|
86
|
+
{
|
|
87
|
+
NSPasteboard *pb = NSPasteboard.generalPasteboard;
|
|
88
|
+
if ([type.lowercaseString isEqualToString:@"plaintext"]) {
|
|
89
|
+
if ([pb.types containsObject:NSPasteboardTypeString]) {
|
|
90
|
+
NSString* result = [pb stringForType:NSPasteboardTypeString];
|
|
91
|
+
return [result dataUsingEncoding:NSUTF8StringEncoding];
|
|
92
|
+
}
|
|
93
|
+
} else if ([type.lowercaseString isEqualToString:@"image"]) {
|
|
94
|
+
NSData *imageData = nil;
|
|
95
|
+
|
|
96
|
+
for (NSPasteboardType pbType in @[NSPasteboardTypePNG, NSPasteboardTypeTIFF]) {
|
|
97
|
+
if ([pb.types containsObject:pbType]) {
|
|
98
|
+
imageData = [pb dataForType:pbType];
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (nil != imageData) {
|
|
104
|
+
NSImage *image = [[NSImage alloc] initWithData:imageData];
|
|
105
|
+
if (nil != image) {
|
|
106
|
+
NSArray *reps = [image representations];
|
|
107
|
+
if ([reps count] > 0 && [reps[0] isKindOfClass:[NSBitmapImageRep class]]) {
|
|
108
|
+
NSBitmapImageRep *bitmapRep = (NSBitmapImageRep *)reps[0];
|
|
109
|
+
return [bitmapRep representationUsingType:NSBitmapImageFileTypePNG properties:@{}];
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
} else if ([type.lowercaseString isEqualToString:@"url"]) {
|
|
114
|
+
if ([pb.types containsObject:NSPasteboardTypeURL]) {
|
|
115
|
+
NSString* result = [pb stringForType:NSPasteboardTypeURL];
|
|
116
|
+
return [result dataUsingEncoding:NSUTF8StringEncoding];
|
|
117
|
+
}
|
|
118
|
+
} else {
|
|
119
|
+
NSString *description = [NSString stringWithFormat:@"Unsupported content type: %@", type];
|
|
120
|
+
if (error) {
|
|
121
|
+
*error = [[FBErrorBuilder.builder withDescription:description] build];
|
|
122
|
+
}
|
|
123
|
+
return nil;
|
|
124
|
+
}
|
|
125
|
+
return [@"" dataUsingEncoding:NSUTF8StringEncoding];
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
@end
|
|
@@ -22,7 +22,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
22
22
|
|
|
23
23
|
/** YES if the corresponding screen is a main screen */
|
|
24
24
|
@property (readonly, nonatomic) BOOL isMain;
|
|
25
|
-
/** The integer
|
|
25
|
+
/** The integer identifier of a screen */
|
|
26
26
|
@property (readonly, nonatomic) long long identifier;
|
|
27
27
|
|
|
28
28
|
@end
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
NS_ASSUME_NONNULL_BEGIN
|
|
20
20
|
|
|
21
|
-
/*!Controls elements binding strategy. By default elements are bind by
|
|
21
|
+
/*!Controls elements binding strategy. By default elements are bind by accessibility identifier */
|
|
22
22
|
extern NSString* const AM_BOUND_ELEMENTS_BY_INDEX_SETTING;
|
|
23
23
|
|
|
24
24
|
/*!Whether to use the default XCTest UI interruptions hanfling (YES by default).
|
|
@@ -21,11 +21,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
21
21
|
@interface AMSnapshotUtils : NSObject
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
|
-
|
|
24
|
+
Retrieves the unique snapshot hash. This hash is unique per snapshot's
|
|
25
25
|
accessibility elemnent, which means different snapshots of the same
|
|
26
26
|
element may have equal hashes
|
|
27
27
|
|
|
28
|
-
@param snapshot snapshot instance to
|
|
28
|
+
@param snapshot snapshot instance to calculate the hash for
|
|
29
29
|
@return The hash value as base64-encoded string
|
|
30
30
|
*/
|
|
31
31
|
+ (NSString *)hashWithSnapshot:(id)snapshot;
|
|
@@ -23,14 +23,14 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
23
23
|
@property (nonatomic) double offset;
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
Get the name of the corresponding raw action item. This method is expected to be
|
|
27
|
-
|
|
28
|
-
@return The corresponding action item key in object's raw JSON
|
|
26
|
+
Get the name of the corresponding raw action item. This method is expected to be overridden in subclasses.
|
|
27
|
+
|
|
28
|
+
@return The corresponding action item key in object's raw JSON representation
|
|
29
29
|
*/
|
|
30
30
|
+ (NSString *)actionName;
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
|
-
Add the current gesture to XCPointerEventPath instance. This method is expected to be
|
|
33
|
+
Add the current gesture to XCPointerEventPath instance. This method is expected to be overridden in subclasses.
|
|
34
34
|
|
|
35
35
|
@param eventPath The destination XCPointerEventPath instance. If nil value is passed then a new XCPointerEventPath instance is going to be created
|
|
36
36
|
@param allItems The existing actions chain to be transformed into event path
|
|
@@ -66,7 +66,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
66
66
|
Calculate absolute gesture position on the screen based on provided element and positionOffset values.
|
|
67
67
|
|
|
68
68
|
@param element The element instance to perform the gesture on. If element equals to nil then positionOffset is considered as absolute coordinates
|
|
69
|
-
@param positionOffset The actual coordinate offset. If this
|
|
69
|
+
@param positionOffset The actual coordinate offset. If this value equals to nil then element's hitpoint is taken as gesture position. If element is not nil then this offset is calculated relatively to the top-left cordner of the element's position
|
|
70
70
|
@param error If there is an error, upon return contains an NSError object that describes the problem
|
|
71
71
|
@return Adbsolute gesture position on the screen or nil if the calculation fails (for example, the element is invisible)
|
|
72
72
|
*/
|
|
@@ -85,7 +85,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
85
85
|
@property (nonatomic) double durationOffset;
|
|
86
86
|
|
|
87
87
|
/**
|
|
88
|
-
Add a new gesture item to the current chain. The method is expected to be
|
|
88
|
+
Add a new gesture item to the current chain. The method is expected to be overridden in subclasses.
|
|
89
89
|
|
|
90
90
|
@param item The actual gesture instance to be added
|
|
91
91
|
*/
|
|
@@ -113,8 +113,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
113
113
|
|
|
114
114
|
/**
|
|
115
115
|
Initializes actions synthesizer. This initializer should be used only by subclasses.
|
|
116
|
-
|
|
117
|
-
@param actions The raw actions chain received from request's JSON. The format of this chain is defined by the standard, implemented in the
|
|
116
|
+
|
|
117
|
+
@param actions The raw actions chain received from request's JSON. The format of this chain is defined by the standard, implemented in the corresponding subclass.
|
|
118
118
|
@param application Current application instance
|
|
119
119
|
@param elementCache Elements cache, which is used to replace elements references in the chain with their instances. We assume the chain already contains element instances if this parameter is set to nil
|
|
120
120
|
@param error If there is an error, upon return contains an NSError object that describes the problem
|
|
@@ -126,7 +126,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
126
126
|
error:(NSError **)error;
|
|
127
127
|
|
|
128
128
|
/**
|
|
129
|
-
Synthesizes XCTest-compatible event record to be performed in the UI. This method is supposed to be
|
|
129
|
+
Synthesizes XCTest-compatible event record to be performed in the UI. This method is supposed to be overridden by subclasses.
|
|
130
130
|
|
|
131
131
|
@param error If there is an error, upon return contains an NSError object that describes the problem
|
|
132
132
|
@return The generated event record or nil in case of failure
|