appium-mac2-driver 2.0.0 → 2.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 (48) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +81 -2
  3. package/WebDriverAgentMac/IntegrationTests/AMVideoRecordingTests.m +57 -0
  4. package/WebDriverAgentMac/WebDriverAgentLib/Commands/AMVideoCommands.h +27 -0
  5. package/WebDriverAgentMac/WebDriverAgentLib/Commands/AMVideoCommands.m +120 -0
  6. package/WebDriverAgentMac/WebDriverAgentLib/Commands/FBDebugCommands.m +17 -0
  7. package/WebDriverAgentMac/WebDriverAgentLib/Commands/FBScreenshotCommands.m +8 -8
  8. package/WebDriverAgentMac/WebDriverAgentLib/Routing/AMXCTRunnerDaemonSession.h +31 -0
  9. package/WebDriverAgentMac/WebDriverAgentLib/Routing/AMXCTRunnerDaemonSessionWrapper.h +39 -0
  10. package/WebDriverAgentMac/WebDriverAgentLib/Routing/AMXCTRunnerDaemonSessionWrapper.m +43 -0
  11. package/WebDriverAgentMac/WebDriverAgentLib/Routing/FBScreenRecordingContainer.h +59 -0
  12. package/WebDriverAgentMac/WebDriverAgentLib/Routing/FBScreenRecordingContainer.m +74 -0
  13. package/WebDriverAgentMac/WebDriverAgentLib/Routing/FBScreenRecordingPromise.h +34 -0
  14. package/WebDriverAgentMac/WebDriverAgentLib/Routing/FBScreenRecordingPromise.m +32 -0
  15. package/WebDriverAgentMac/WebDriverAgentLib/Routing/FBScreenRecordingRequest.h +44 -0
  16. package/WebDriverAgentMac/WebDriverAgentLib/Routing/FBScreenRecordingRequest.m +97 -0
  17. package/WebDriverAgentMac/WebDriverAgentLib/Routing/FBSession.m +14 -0
  18. package/WebDriverAgentMac/WebDriverAgentLib/Utilities/AMScreenUtils.h +49 -0
  19. package/WebDriverAgentMac/WebDriverAgentLib/Utilities/AMScreenUtils.m +49 -0
  20. package/WebDriverAgentMac/WebDriverAgentLib/Utilities/AMVideoRecorder.h +50 -0
  21. package/WebDriverAgentMac/WebDriverAgentLib/Utilities/AMVideoRecorder.m +112 -0
  22. package/WebDriverAgentMac/WebDriverAgentMac.xcodeproj/project.pbxproj +64 -0
  23. package/build/lib/commands/helpers.d.ts +4 -0
  24. package/build/lib/commands/helpers.d.ts.map +1 -0
  25. package/build/lib/commands/helpers.js +28 -0
  26. package/build/lib/commands/helpers.js.map +1 -0
  27. package/build/lib/commands/native-record-screen.d.ts +75 -0
  28. package/build/lib/commands/native-record-screen.d.ts.map +1 -0
  29. package/build/lib/commands/native-record-screen.js +139 -0
  30. package/build/lib/commands/native-record-screen.js.map +1 -0
  31. package/build/lib/commands/record-screen.d.ts.map +1 -1
  32. package/build/lib/commands/record-screen.js +2 -28
  33. package/build/lib/commands/record-screen.js.map +1 -1
  34. package/build/lib/driver.d.ts +25 -0
  35. package/build/lib/driver.d.ts.map +1 -1
  36. package/build/lib/driver.js +13 -0
  37. package/build/lib/driver.js.map +1 -1
  38. package/build/lib/execute-method-map.d.ts +18 -0
  39. package/build/lib/execute-method-map.d.ts.map +1 -1
  40. package/build/lib/execute-method-map.js +30 -0
  41. package/build/lib/execute-method-map.js.map +1 -1
  42. package/lib/commands/helpers.ts +30 -0
  43. package/lib/commands/native-record-screen.ts +180 -0
  44. package/lib/commands/record-screen.js +2 -30
  45. package/lib/driver.js +18 -0
  46. package/lib/execute-method-map.ts +30 -0
  47. package/npm-shrinkwrap.json +2 -2
  48. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## [2.1.0](https://github.com/appium/appium-mac2-driver/compare/v2.0.0...v2.1.0) (2025-02-07)
2
+
3
+
4
+ ### Features
5
+
6
+ * Add support for native screen recording ([#330](https://github.com/appium/appium-mac2-driver/issues/330)) ([d2f5b25](https://github.com/appium/appium-mac2-driver/commit/d2f5b2564f4b25fefbcce60d77718031d438bf60))
7
+
1
8
  ## [2.0.0](https://github.com/appium/appium-mac2-driver/compare/v1.20.5...v2.0.0) (2025-02-06)
2
9
 
3
10
 
package/README.md CHANGED
@@ -586,7 +586,7 @@ Retrieves a screenshot of each display available to macOS.
586
586
 
587
587
  Name | Type | Required | Description | Example
588
588
  --- | --- | --- | --- | ---
589
- displayId | number | no | Display identifier to take a screenshot for. If not provided then all display screenshots are going to be returned. If no matches were found then an error is thrown. | 1
589
+ displayId | number | no | Display identifier to take a screenshot for. If not provided then all display screenshots are going to be returned. If no matches were found then an error is thrown. Use the `system_profiler -json SPDisplaysDataType` Terminal command to list IDs of connected displays or the [macos: listDisplays](#macos-listdisplays) API. | 1
590
590
 
591
591
  #### Returns
592
592
 
@@ -595,7 +595,7 @@ A list of dictionaries where each item has the following keys:
595
595
  - `isMain`: Whether this display is the main one
596
596
  - `payload`: The actual PNG screenshot data encoded to base64 string
597
597
 
598
- ### mobile: deepLink
598
+ ### macos: deepLink
599
599
 
600
600
  Opens the given URL with the default or the given application.
601
601
  Xcode must be at version 14.3+.
@@ -607,6 +607,85 @@ Name | Type | Required | Description | Example
607
607
  url | string | yes | The URL to be opened. This parameter is manadatory. | https://apple.com, myscheme:yolo
608
608
  bundleId | string | no | The bundle identifier of an application to open the given url with. If not provided then the default application for the given url scheme is going to be used. | com.myapp.yolo
609
609
 
610
+ ### macos: startNativeScreenRecording
611
+
612
+ Initiates a new native screen recording session via XCTest.
613
+ If the screen recording is already running then this call results in noop.
614
+ A screen recording is running until a testing session is finished.
615
+ If a recording has never been stopped explicitly during a test session
616
+ then it would be stopped automatically upon the test session termination,
617
+ and leftover videos would be deleted as well.
618
+ Xcode must be at version 15+.
619
+
620
+ #### Arguments
621
+
622
+ Name | Type | Required | Description | Example
623
+ --- | --- | --- | --- | ---
624
+ fps | number | no | Frame Per Second setting for the resulting screen recording. 24 by default. Higher FPS values may significantly increase the size of the resulting video. | 60
625
+ codec | number | no | Possible codec value, where `0` means H264 (the default setting), `1` means HEVC | 1
626
+ displayId | number | no | Valid display identifier to record the video from. Main display ID is assumed by default. Use the `system_profiler -json SPDisplaysDataType` Terminal command to list IDs of connected displays or the [macos: listDisplays](#macos-listdisplays) API. | 1
627
+
628
+ #### Returns
629
+
630
+ The information about the asynchronously running video recording, which includes the following items:
631
+
632
+ Name | Type | Description | Example
633
+ --- | --- | --- | ---
634
+ fps | number | Frame Per Second value | 24
635
+ codec | number | Codec value, where `0` means H264 (the default setting), `1` means HEVC | 1
636
+ displayId | number | Display identifier used to record this video for. | 1
637
+ uuid | string | Unique video identifier. It is also used by XCTest to store the video on the file system. Look for `$HOME/Library/Daemon Containers/<testmanager_id>/Data/Attachments/<uuid>` to find the appropriate video file. Add the `.mp4` extension to it to make it openable by video players.
638
+ startedAt | number | Unix timestamp of the video startup moment | 123456789
639
+
640
+ ### macos: getNativeScreenRecordingInfo
641
+
642
+ Fetches the information of the currently running native video recording.
643
+ Xcode must be at version 15+.
644
+
645
+ #### Returns
646
+
647
+ Either `null` if no native video recording is currently active or the same map that [macos: startNativeScreenRecording](#macos-startnativescreenrecording) returns.
648
+
649
+ ### macos: stopNativeScreenRecording
650
+
651
+ Stops native screen recording previously started by
652
+ [macos: startNativeScreenRecording](#macos-startnativescreenrecording)
653
+ and returns the video payload or uploads it to a remote location,
654
+ depending on the provided arguments.
655
+ The actual video file is removed from the local file system after the video payload is
656
+ successfully consumed.
657
+ If no screen recording has been started before then this API throws an exception.
658
+ Xcode must be at version 15+.
659
+
660
+ #### Arguments
661
+
662
+ Name | Type | Required | Description | Example
663
+ --- | --- | --- | --- | ---
664
+ remotePath | string | no | The path to the remote location, where the resulting video should be uploaded. The following protocols are supported: http/https, ftp. Null or empty string value (the default setting) means the content of resulting file should be encoded as Base64 and passed as the endpoint response value. An exception will be thrown if the generated media file is too big to fit into the available process memory. | https://myserver.com/upload/video.mp4
665
+ user | string | no | The name of the user for the remote authentication. | myname
666
+ pass | string | no | The password for the remote authentication. | mypassword
667
+ method | string | no | The http multipart upload method name. The 'PUT' one is used by default. | POST
668
+ headers | map | no | Additional headers mapping for multipart http(s) uploads | `{"header": "value"}`
669
+ fileFieldName | string | no | The name of the form field, where the file content BLOB should be stored for http(s) uploads. `file` by default | payload
670
+ formFields | Map or `Array<Pair>` | no | Additional form fields for multipart http(s) uploads | `{"field1": "value1", "field2": "value2"}` or `[["field1", "value1"], ["field2", "value2"]]`
671
+
672
+ #### Returns
673
+
674
+ Base64-encoded content of the recorded media file if `remotePath` parameter is falsy or an empty string.
675
+
676
+ ### macos: listDisplays
677
+
678
+ Fetches information about available displays.
679
+
680
+ #### Returns
681
+
682
+ A map where keys are display identifiers represented as strings and values are display infos containing the following items:
683
+
684
+ Name | Type | Description | Example
685
+ --- | --- | --- | ---
686
+ id | number | Display identifier | 12345
687
+ isMain | boolean | Is `true` if the display is configured as a main system display | false
688
+
610
689
 
611
690
  ## Application Under Test Concept
612
691
 
@@ -0,0 +1,57 @@
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 "AMVideoRecorder.h"
21
+ #import "FBScreenRecordingRequest.h"
22
+ #import "FBTestMacros.h"
23
+ #import "FBScreenRecordingContainer.h"
24
+ #import "FBScreenRecordingPromise.h"
25
+
26
+
27
+ @interface AMVideoRecordingTests : AMIntegrationTestCase
28
+ @end
29
+
30
+ @implementation AMVideoRecordingTests
31
+
32
+ - (void)setUp
33
+ {
34
+ [super setUp];
35
+ static dispatch_once_t onceToken;
36
+ dispatch_once(&onceToken, ^{
37
+ [self launchApplication];
38
+ });
39
+ }
40
+
41
+ - (void)testVideoRecording
42
+ {
43
+ AMVideoRecorder *recorder = AMVideoRecorder.sharedInstance;
44
+ FBScreenRecordingRequest *request = [[FBScreenRecordingRequest alloc] initWithFps:24
45
+ codec:0
46
+ displayID:nil];
47
+ NSError *error;
48
+ FBScreenRecordingPromise *promise = [recorder startScreenRecordingWithRequest:request
49
+ error:&error];
50
+ XCTAssertNotNil(promise);
51
+ XCTAssertNil(error);
52
+ FBWaitExact(5);
53
+ XCTAssertTrue([recorder stopScreenRecordingWithUUID:promise.identifier error:&error]);
54
+ XCTAssertNil(error);
55
+ }
56
+
57
+ @end
@@ -0,0 +1,27 @@
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 <Foundation/Foundation.h>
18
+
19
+ #import <WebDriverAgentLib/FBCommandHandler.h>
20
+
21
+ NS_ASSUME_NONNULL_BEGIN
22
+
23
+ @interface AMVideoCommands : NSObject <FBCommandHandler>
24
+
25
+ @end
26
+
27
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,120 @@
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 "AMVideoCommands.h"
18
+
19
+ #import "FBRouteRequest.h"
20
+ #import "FBScreenRecordingContainer.h"
21
+ #import "FBScreenRecordingPromise.h"
22
+ #import "FBScreenRecordingRequest.h"
23
+ #import "AMScreenUtils.h"
24
+ #import "FBSession.h"
25
+ #import "AMVideoRecorder.h"
26
+ #import "FBErrorBuilder.h"
27
+
28
+ const NSUInteger DEFAULT_FPS = 24;
29
+ const NSUInteger DEFAULT_CODEC = 0;
30
+
31
+ @implementation AMVideoCommands
32
+
33
+ + (NSArray *)routes
34
+ {
35
+ return
36
+ @[
37
+ [[FBRoute POST:@"/wda/video/start"] respondWithTarget:self action:@selector(handleStartVideoRecording:)],
38
+ [[FBRoute POST:@"/wda/video/stop"] respondWithTarget:self action:@selector(handleStopVideoRecording:)],
39
+ [[FBRoute GET:@"/wda/video"] respondWithTarget:self action:@selector(handleGetVideoRecording:)],
40
+
41
+ [[FBRoute POST:@"/wda/video/start"].withoutSession respondWithTarget:self action:@selector(handleStartVideoRecording:)],
42
+ [[FBRoute POST:@"/wda/video/stop"].withoutSession respondWithTarget:self action:@selector(handleStopVideoRecording:)],
43
+ [[FBRoute GET:@"/wda/video"].withoutSession respondWithTarget:self action:@selector(handleGetVideoRecording:)],
44
+ ];
45
+ }
46
+
47
+ + (id<FBResponsePayload>)handleStartVideoRecording:(FBRouteRequest *)request
48
+ {
49
+ FBScreenRecordingPromise *activeScreenRecording = FBScreenRecordingContainer.sharedInstance.screenRecordingPromise;
50
+ if (nil != activeScreenRecording) {
51
+ return FBResponseWithObject([FBScreenRecordingContainer.sharedInstance toDictionary] ?: [NSNull null]);
52
+ }
53
+
54
+ NSNumber *fps = (NSNumber *)request.arguments[@"fps"] ?: @(DEFAULT_FPS);
55
+ NSNumber *codec = (NSNumber *)request.arguments[@"codec"] ?: @(DEFAULT_CODEC);
56
+ NSNumber *displayID = (NSNumber *)request.arguments[@"displayId"];
57
+ if (nil != displayID) {
58
+ NSError *error;
59
+ if (![self verifyDisplayWithID:displayID.longLongValue error:&error]) {
60
+ return FBResponseWithStatus([FBCommandStatus invalidArgumentErrorWithMessage:error.description
61
+ traceback:nil]);
62
+ }
63
+ }
64
+ FBScreenRecordingRequest *recordingRequest = [[FBScreenRecordingRequest alloc] initWithFps:fps.integerValue
65
+ codec:codec.longLongValue
66
+ displayID:displayID];
67
+ NSError *error;
68
+ FBScreenRecordingPromise* promise = [AMVideoRecorder.sharedInstance startScreenRecordingWithRequest:recordingRequest
69
+ error:&error];
70
+ if (nil == promise) {
71
+ [FBScreenRecordingContainer.sharedInstance reset];
72
+ return FBResponseWithUnknownError(error);
73
+ }
74
+ [FBScreenRecordingContainer.sharedInstance storeScreenRecordingPromise:promise
75
+ fps:fps.integerValue
76
+ codec:codec.longLongValue
77
+ displayID:displayID];
78
+ return FBResponseWithObject([FBScreenRecordingContainer.sharedInstance toDictionary]);
79
+ }
80
+
81
+ + (id<FBResponsePayload>)handleStopVideoRecording:(FBRouteRequest *)request
82
+ {
83
+ FBScreenRecordingPromise *activeScreenRecording = FBScreenRecordingContainer.sharedInstance.screenRecordingPromise;
84
+ if (nil == activeScreenRecording) {
85
+ return FBResponseWithOK();
86
+ }
87
+
88
+ NSUUID *recordingId = activeScreenRecording.identifier;
89
+ NSDictionary *response = [FBScreenRecordingContainer.sharedInstance toDictionary];
90
+ NSError *error;
91
+ if (![AMVideoRecorder.sharedInstance stopScreenRecordingWithUUID:recordingId error:&error]) {
92
+ [FBScreenRecordingContainer.sharedInstance reset];
93
+ return FBResponseWithUnknownError(error);
94
+ }
95
+ [FBScreenRecordingContainer.sharedInstance reset];
96
+ return FBResponseWithObject(response);
97
+ }
98
+
99
+ + (id<FBResponsePayload>)handleGetVideoRecording:(FBRouteRequest *)request
100
+ {
101
+ return FBResponseWithObject([FBScreenRecordingContainer.sharedInstance toDictionary] ?: [NSNull null]);
102
+ }
103
+
104
+ + (BOOL)verifyDisplayWithID:(long long)displayID error:(NSError **)error
105
+ {
106
+ NSMutableArray* availableIds = [NSMutableArray array];
107
+ for (XCUIScreen *screen in XCUIScreen.screens) {
108
+ long long currentDisplayId = AMFetchScreenId(screen);
109
+ if (displayID == currentDisplayId) {
110
+ return YES;
111
+ }
112
+ [availableIds addObject:@(currentDisplayId)];
113
+ }
114
+ return [[[FBErrorBuilder builder]
115
+ withDescriptionFormat:@"The provided display identifier %lld is not known. Only the following values are allowed: %@",
116
+ displayID, [availableIds componentsJoinedByString:@","]]
117
+ buildError:error];
118
+ }
119
+
120
+ @end
@@ -9,6 +9,7 @@
9
9
 
10
10
  #import "FBDebugCommands.h"
11
11
 
12
+ #import "AMScreenUtils.h"
12
13
  #import "FBRouteRequest.h"
13
14
  #import "FBSession.h"
14
15
  #import "XCUIApplication+AMSource.h"
@@ -23,6 +24,9 @@
23
24
  @[
24
25
  [[FBRoute GET:@"/source"] respondWithTarget:self action:@selector(handleGetSourceCommand:)],
25
26
  [[FBRoute GET:@"/source"].withoutSession respondWithTarget:self action:@selector(handleGetSourceCommand:)],
27
+
28
+ [[FBRoute GET:@"/wda/displays/list"] respondWithTarget:self action:@selector(handleListDisplays:)],
29
+ [[FBRoute GET:@"/wda/displays/list"].withoutSession respondWithTarget:self action:@selector(handleListDisplays:)],
26
30
  ];
27
31
  }
28
32
 
@@ -53,4 +57,17 @@ static NSString *const SOURCE_FORMAT_DESCRIPTION = @"description";
53
57
  return FBResponseWithObject(result);
54
58
  }
55
59
 
60
+ + (id<FBResponsePayload>)handleListDisplays:(FBRouteRequest *)request
61
+ {
62
+ NSArray<AMScreenProperties *> *screenInfos = AMListScreens();
63
+ NSMutableDictionary <NSString *, NSDictionary<NSString *, id> *> *result = [NSMutableDictionary new];
64
+ for (AMScreenProperties *screenInfo in screenInfos) {
65
+ result[[NSString stringWithFormat:@"%lld", screenInfo.identifier]] = @{
66
+ @"id": @(screenInfo.identifier),
67
+ @"isMain": @(screenInfo.isMain),
68
+ };
69
+ }
70
+ return FBResponseWithObject(result.copy);
71
+ }
72
+
56
73
  @end
@@ -9,7 +9,7 @@
9
9
 
10
10
  #import "FBScreenshotCommands.h"
11
11
 
12
- #import "XCTest/XCTest.h"
12
+ #import "AMScreenUtils.h"
13
13
  #import "FBRouteRequest.h"
14
14
 
15
15
  @implementation FBScreenshotCommands
@@ -49,21 +49,21 @@
49
49
  NSMutableDictionary <NSString *, NSDictionary<NSString *, id> *> *result = [NSMutableDictionary new];
50
50
  NSMutableArray <NSNumber *> *availableDisplayIds = [NSMutableArray new];
51
51
  for (XCUIScreen *screen in XCUIScreen.screens) {
52
- NSNumber *displayId = [screen valueForKey:@"_displayID"];
53
- if (nil == displayId || (nil != desiredId && ![desiredId isEqualToNumber:displayId])) {
52
+ long long currentScreenId = AMFetchScreenId(screen);
53
+ if (nil != desiredId && desiredId.longLongValue != currentScreenId) {
54
54
  continue;
55
55
  }
56
56
 
57
- [availableDisplayIds addObject:displayId];
58
- result[displayId.stringValue] = @{
59
- @"id": displayId,
60
- @"isMain": [screen valueForKey:@"_isMainScreen"] ?: NSNull.null,
57
+ [availableDisplayIds addObject:@(currentScreenId)];
58
+ result[[NSString stringWithFormat:@"%lld", currentScreenId]] = @{
59
+ @"id": @(currentScreenId),
60
+ @"isMain": @(AMIsMainScreen(screen)),
61
61
  @"payload": [screen.screenshot.PNGRepresentation base64EncodedStringWithOptions:0] ?: NSNull.null
62
62
  };
63
63
  }
64
64
  if (nil != desiredId && 0 == [result count]) {
65
65
  NSString *message = [NSString stringWithFormat:@"The screen identified by %@ is not available to XCTest. Only the following identifiers are available: %@",
66
- desiredId, availableDisplayIds];
66
+ desiredId, [availableDisplayIds componentsJoinedByString:@","]];
67
67
  return FBResponseWithStatus([FBCommandStatus unableToCaptureScreenErrorWithMessage:message
68
68
  traceback:nil]);
69
69
  }
@@ -0,0 +1,31 @@
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
+ NS_ASSUME_NONNULL_BEGIN
20
+
21
+ @protocol AMXCTRunnerDaemonSession
22
+
23
+ - (void)stopScreenRecordingWithUUID:(NSUUID *)arg1
24
+ withReply:(void (^)(NSError *))arg2;
25
+ - (void)startScreenRecordingWithRequest:(id/* XCTScreenRecordingRequest */)arg1
26
+ withReply:(void (^)(id/* XCTAttachmentFutureMetadata */, NSError *))arg2;
27
+ - (_Bool)supportsScreenRecording;
28
+
29
+ @end
30
+
31
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,39 @@
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 <Foundation/Foundation.h>
18
+
19
+ @protocol AMXCTRunnerDaemonSession;
20
+
21
+ NS_ASSUME_NONNULL_BEGIN
22
+
23
+ @interface AMXCTRunnerDaemonSessionWrapper : NSObject
24
+
25
+ + (instancetype)sharedInstance;
26
+
27
+ /**
28
+ @return YES if the current Xcode SDK supports video recording
29
+ */
30
+ - (BOOL)canRecordVideo;
31
+
32
+ /**
33
+ @returns The internal XCTest daemon session instance
34
+ */
35
+ - (id<AMXCTRunnerDaemonSession>)daemonSession;
36
+
37
+ @end
38
+
39
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,43 @@
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 "AMXCTRunnerDaemonSessionWrapper.h"
18
+
19
+ #import "AMXCTRunnerDaemonSession.h"
20
+
21
+ @implementation AMXCTRunnerDaemonSessionWrapper
22
+
23
+ + (instancetype)sharedInstance
24
+ {
25
+ static AMXCTRunnerDaemonSessionWrapper *instance;
26
+ static dispatch_once_t onceToken;
27
+ dispatch_once(&onceToken, ^{
28
+ instance = [[self alloc] init];
29
+ });
30
+ return instance;
31
+ }
32
+
33
+ - (id<AMXCTRunnerDaemonSession>)daemonSession
34
+ {
35
+ return (id)[NSClassFromString(@"XCTRunnerDaemonSession") sharedSession];
36
+ }
37
+
38
+ - (BOOL)canRecordVideo
39
+ {
40
+ return [(NSObject *)self.daemonSession respondsToSelector:@selector(startScreenRecordingWithRequest:withReply:)];
41
+ }
42
+
43
+ @end
@@ -0,0 +1,59 @@
1
+ /**
2
+ *
3
+ * Copyright (c) 2015-present, Facebook, Inc.
4
+ * All rights reserved.
5
+ *
6
+ * This source code is licensed under the BSD-style license found in the
7
+ * LICENSE file in the root directory of this source tree. An additional grant
8
+ * of patent rights can be found in the PATENTS file in the same directory.
9
+ */
10
+
11
+ #import <Foundation/Foundation.h>
12
+
13
+ NS_ASSUME_NONNULL_BEGIN
14
+
15
+ @class FBScreenRecordingPromise;
16
+
17
+ @interface FBScreenRecordingContainer : NSObject
18
+
19
+ /** The amount of video FPS */
20
+ @property (readonly, nonatomic) NSUInteger fps;
21
+ /** Codec to use, where 0 is h264, 1 - HEVC */
22
+ @property (readonly, nonatomic) long long codec;
23
+ @property (readonly, nonatomic, nullable) NSNumber *displayID;
24
+ /** Keep the currently active screen resording promise. Equals to nil if no active screen recordings are running */
25
+ @property (readonly, nonatomic, nullable) FBScreenRecordingPromise* screenRecordingPromise;
26
+ /** The timestamp of the video startup as Unix float seconds */
27
+ @property (readonly, nonatomic, nullable) NSNumber *startedAt;
28
+
29
+ /**
30
+ @return singleton instance
31
+ */
32
+ + (instancetype)sharedInstance;
33
+
34
+ /**
35
+ Keeps current screen recording promise
36
+
37
+ @param screenRecordingPromise a promise to set
38
+ @param fps FPS value
39
+ @param codec Codec value
40
+ */
41
+ - (void)storeScreenRecordingPromise:(FBScreenRecordingPromise *)screenRecordingPromise
42
+ fps:(NSUInteger)fps
43
+ codec:(long long)codec
44
+ displayID:(nullable NSNumber *)displayID;
45
+ /**
46
+ Resets the current screen recording promise
47
+ */
48
+ - (void)reset;
49
+
50
+ /**
51
+ Transforms the container content to a dictionary.
52
+
53
+ @return May return nil if no screen recording is currently running
54
+ */
55
+ - (nullable NSDictionary *)toDictionary;
56
+
57
+ @end
58
+
59
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,74 @@
1
+ /**
2
+ *
3
+ * Copyright (c) 2015-present, Facebook, Inc.
4
+ * All rights reserved.
5
+ *
6
+ * This source code is licensed under the BSD-style license found in the
7
+ * LICENSE file in the root directory of this source tree. An additional grant
8
+ * of patent rights can be found in the PATENTS file in the same directory.
9
+ */
10
+
11
+ #import "FBScreenRecordingContainer.h"
12
+
13
+ #import "AMScreenUtils.h"
14
+ #import "FBScreenRecordingPromise.h"
15
+
16
+ @interface FBScreenRecordingContainer ()
17
+
18
+ @property (readwrite) NSUInteger fps;
19
+ @property (readwrite) long long codec;
20
+ @property (readwrite) NSNumber *displayID;
21
+ @property (readwrite) FBScreenRecordingPromise* screenRecordingPromise;
22
+ @property (readwrite) NSNumber *startedAt;
23
+
24
+ @end
25
+
26
+ @implementation FBScreenRecordingContainer
27
+
28
+ + (instancetype)sharedInstance
29
+ {
30
+ static FBScreenRecordingContainer *instance;
31
+ static dispatch_once_t onceToken;
32
+ dispatch_once(&onceToken, ^{
33
+ instance = [[self alloc] init];
34
+ });
35
+ return instance;
36
+ }
37
+
38
+ - (void)storeScreenRecordingPromise:(FBScreenRecordingPromise *)screenRecordingPromise
39
+ fps:(NSUInteger)fps
40
+ codec:(long long)codec
41
+ displayID:(nullable NSNumber *)displayID
42
+ {
43
+ self.fps = fps;
44
+ self.codec = codec;
45
+ self.displayID = displayID;
46
+ self.screenRecordingPromise = screenRecordingPromise;
47
+ self.startedAt = @([NSDate.date timeIntervalSince1970]);
48
+ }
49
+
50
+ - (void)reset;
51
+ {
52
+ self.fps = 0;
53
+ self.codec = 0;
54
+ self.displayID = nil;
55
+ self.screenRecordingPromise = nil;
56
+ self.startedAt = nil;
57
+ }
58
+
59
+ - (nullable NSDictionary *)toDictionary
60
+ {
61
+ if (nil == self.screenRecordingPromise) {
62
+ return nil;
63
+ }
64
+
65
+ return @{
66
+ @"fps": @(self.fps),
67
+ @"codec": @(self.codec),
68
+ @"displayId": self.displayID ?: @(AMFetchScreenId(XCUIScreen.mainScreen)),
69
+ @"uuid": [self.screenRecordingPromise identifier].UUIDString ?: [NSNull null],
70
+ @"startedAt": self.startedAt ?: [NSNull null],
71
+ };
72
+ }
73
+
74
+ @end
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Copyright (c) 2015-present, Facebook, Inc.
3
+ * All rights reserved.
4
+ *
5
+ * This source code is licensed under the BSD-style license found in the
6
+ * LICENSE file in the root directory of this source tree. An additional grant
7
+ * of patent rights can be found in the PATENTS file in the same directory.
8
+ */
9
+
10
+ #import <XCTest/XCTest.h>
11
+
12
+ NS_ASSUME_NONNULL_BEGIN
13
+
14
+ @interface FBScreenRecordingPromise : NSObject
15
+
16
+ /** Unique identiifier of the video recording, also used as the default file name */
17
+ @property (nonatomic, readonly) NSUUID *identifier;
18
+ /** Native screen recording promise */
19
+ @property (nonatomic, readonly) id nativePromise;
20
+
21
+ /**
22
+ Creates a wrapper object for a native screen recording promise.
23
+ The actual screen recording file is stored as
24
+ $HOME/Library/Daemon Containers/<testmanagerd_id>Data/Attachments/<recording_id>
25
+ although this path is not is not accessible directly from within the XCTest container,
26
+ and must be accessed from elsewhere.
27
+
28
+ @param promise Native promise object to be wrapped
29
+ */
30
+ - (instancetype)initWithNativePromise:(id)promise;
31
+
32
+ @end
33
+
34
+ NS_ASSUME_NONNULL_END