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.
Files changed (52) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +27 -1
  3. package/WebDriverAgentMac/IntegrationTests/AMPasteboardTests.m +111 -0
  4. package/WebDriverAgentMac/IntegrationTests/AMW3CActionsTests.m +1 -1
  5. package/WebDriverAgentMac/WebDriverAgentLib/Categories/XCUIApplication+AMActiveElement.h +1 -1
  6. package/WebDriverAgentMac/WebDriverAgentLib/Categories/XCUIApplication+AMSource.h +2 -2
  7. package/WebDriverAgentMac/WebDriverAgentLib/Categories/XCUIApplication+FBW3CActions.h +1 -1
  8. package/WebDriverAgentMac/WebDriverAgentLib/Categories/XCUIElementQuery+AMHelpers.h +2 -2
  9. package/WebDriverAgentMac/WebDriverAgentLib/Commands/AMWindowCommands.m +3 -3
  10. package/WebDriverAgentMac/WebDriverAgentLib/Commands/FBCustomCommands.m +33 -0
  11. package/WebDriverAgentMac/WebDriverAgentLib/Routing/FBExceptions.h +3 -3
  12. package/WebDriverAgentMac/WebDriverAgentLib/Routing/FBResponseJSONPayload.h +1 -1
  13. package/WebDriverAgentMac/WebDriverAgentLib/Routing/FBScreenRecordingRequest.h +1 -1
  14. package/WebDriverAgentMac/WebDriverAgentLib/Routing/FBScreenRecordingRequest.m +2 -2
  15. package/WebDriverAgentMac/WebDriverAgentLib/Utilities/AMPasteboard.h +47 -0
  16. package/WebDriverAgentMac/WebDriverAgentLib/Utilities/AMPasteboard.m +128 -0
  17. package/WebDriverAgentMac/WebDriverAgentLib/Utilities/AMScreenUtils.h +1 -1
  18. package/WebDriverAgentMac/WebDriverAgentLib/Utilities/AMSettings.h +1 -1
  19. package/WebDriverAgentMac/WebDriverAgentLib/Utilities/AMSnapshotUtils.h +2 -2
  20. package/WebDriverAgentMac/WebDriverAgentLib/Utilities/FBBaseActionsSynthesizer.h +9 -9
  21. package/WebDriverAgentMac/WebDriverAgentLib/Utilities/FBClassChainQueryParser.h +4 -4
  22. package/WebDriverAgentMac/WebDriverAgentLib/Utilities/FBClassChainQueryParser.m +4 -4
  23. package/WebDriverAgentMac/WebDriverAgentLib/Utilities/FBElementUtils.h +2 -2
  24. package/WebDriverAgentMac/WebDriverAgentLib/Utilities/FBXPath.h +2 -2
  25. package/WebDriverAgentMac/WebDriverAgentLib/Utilities/FBXPath.m +2 -2
  26. package/WebDriverAgentMac/WebDriverAgentMac.xcodeproj/project.pbxproj +12 -0
  27. package/build/lib/commands/clipboard.d.ts +19 -0
  28. package/build/lib/commands/clipboard.d.ts.map +1 -0
  29. package/build/lib/commands/clipboard.js +31 -0
  30. package/build/lib/commands/clipboard.js.map +1 -0
  31. package/build/lib/commands/native-record-screen.js +4 -0
  32. package/build/lib/commands/native-record-screen.js.map +1 -1
  33. package/build/lib/doctor/optional-checks.js +2 -4
  34. package/build/lib/doctor/optional-checks.js.map +1 -1
  35. package/build/lib/doctor/required-checks.js +2 -4
  36. package/build/lib/doctor/required-checks.js.map +1 -1
  37. package/build/lib/driver.d.ts +24 -1
  38. package/build/lib/driver.d.ts.map +1 -1
  39. package/build/lib/driver.js +49 -33
  40. package/build/lib/driver.js.map +1 -1
  41. package/build/lib/execute-method-map.d.ts +13 -0
  42. package/build/lib/execute-method-map.d.ts.map +1 -1
  43. package/build/lib/execute-method-map.js +11 -0
  44. package/build/lib/execute-method-map.js.map +1 -1
  45. package/build/lib/wda-mac.js +6 -2
  46. package/build/lib/wda-mac.js.map +1 -1
  47. package/lib/commands/clipboard.ts +35 -0
  48. package/lib/driver.js +11 -0
  49. package/lib/execute-method-map.ts +11 -0
  50. package/lib/wda-mac.js +2 -2
  51. package/npm-shrinkwrap.json +121 -109
  52. 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 `identifer` attribute case-sensitively. | `⭐⭐⭐⭐⭐` | AppiumBy.accessibilityId("identifier"), By.id("identifier"), By.name("identifier")
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
@@ -136,7 +136,7 @@
136
136
  },
137
137
  ],
138
138
 
139
- // Chain element with singe up action
139
+ // Chain element with single up action
140
140
  @[@{
141
141
  @"type": @"pointer",
142
142
  @"id": @"finger1",
@@ -21,7 +21,7 @@ NS_ASSUME_NONNULL_BEGIN
21
21
  @interface XCUIApplication (AMActiveElement)
22
22
 
23
23
  /**
24
- Retrives the element, which holds the keyboard input focus
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
- Retrives XML application source representation
24
+ Retrieves XML application source representation
25
25
  */
26
26
  - (NSString *)am_xmlRepresentation;
27
27
 
28
28
  /**
29
- Retrives description application source representation.
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 currrent application. The method assumes all elements are already represented by their actual instances if nil value is set
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 ot nil if no element is found
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 ot an empty array if no matches are found
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 correponding button is not available", request.session.currentApplication.description]];
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 correponding button is not available", request.session.currentApplication.description]];
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 correponding button is not available", request.session.currentApplication.description]];
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 happends if the cached element does not exist in DOM anymore
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 happends if the provided XPath expession cannot be compiled because of a syntax error
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 happends if any internal error is triggered during XPath matching procedure
42
+ The exception happens if any internal error is triggered during XPath matching procedure
43
43
  */
44
44
  extern NSString *const FBXPathQueryEvaluationException;
45
45
 
@@ -15,7 +15,7 @@
15
15
  NS_ASSUME_NONNULL_BEGIN
16
16
 
17
17
  /**
18
- Class that represents WebDriverAgent JSON repsonse
18
+ Class that represents WebDriverAgent JSON response
19
19
  */
20
20
  @interface FBResponseJSONPayload : NSObject <FBResponsePayload>
21
21
 
@@ -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 reqeust
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:' contructor is not found on XCTVideoEncoding class"]
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:' contructor is not found on XCTScreenRecordingRequest class"]
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 indentifier of a screen */
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 accessiblity identifier */
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
- Retrives the unique snapshot hash. This hash is unique per snapshot's
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 calcluate the hash for
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 overriden in subclasses.
27
-
28
- @return The corresponding action item key in object's raw JSON reprsentation
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 overriden in subclasses.
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 calue 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
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 overriden in subclasses.
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 correspoding subclass.
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 overriden by subclasses.
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