From b17e52cf440fce1dba4a010f4331eca3faceea1d Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Mon, 5 Aug 2024 10:07:46 +0200 Subject: [PATCH 1/6] feat: Open the default URL in Safari upon session startup --- WebDriverAgent.xcodeproj/project.pbxproj | 12 ++++++++++ .../Commands/FBSessionCommands.m | 13 ++++++++++ WebDriverAgentLib/Routing/FBSession.h | 3 +++ WebDriverAgentLib/Routing/FBSession.m | 2 ++ WebDriverAgentLib/Routing/FBWebServer.m | 3 +++ .../Utilities/FBWebServerParams.h | 23 ++++++++++++++++++ .../Utilities/FBWebServerParams.m | 24 +++++++++++++++++++ .../IntegrationTests/FBSafariAlertTests.m | 6 ++--- 8 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 WebDriverAgentLib/Utilities/FBWebServerParams.h create mode 100644 WebDriverAgentLib/Utilities/FBWebServerParams.m diff --git a/WebDriverAgent.xcodeproj/project.pbxproj b/WebDriverAgent.xcodeproj/project.pbxproj index db4465848..055b0c6b8 100644 --- a/WebDriverAgent.xcodeproj/project.pbxproj +++ b/WebDriverAgent.xcodeproj/project.pbxproj @@ -421,6 +421,10 @@ 7182276E258744C900661B83 /* HTTPErrorResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = E444DC59249131880060D7EB /* HTTPErrorResponse.h */; }; 71822777258744CE00661B83 /* DDNumber.h in Headers */ = {isa = PBXBuildFile; fileRef = E444DC7D249131B00060D7EB /* DDNumber.h */; }; 71822780258744D000661B83 /* DDRange.h in Headers */ = {isa = PBXBuildFile; fileRef = E444DC7B249131B00060D7EB /* DDRange.h */; }; + 718D2C122C60BAE3000788F2 /* FBWebServerParams.m in Sources */ = {isa = PBXBuildFile; fileRef = 718D2C112C60BAE3000788F2 /* FBWebServerParams.m */; }; + 718D2C132C60BAE3000788F2 /* FBWebServerParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 718D2C102C60BAE3000788F2 /* FBWebServerParams.h */; }; + 718D2C142C60BAE3000788F2 /* FBWebServerParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 718D2C102C60BAE3000788F2 /* FBWebServerParams.h */; }; + 718D2C152C60BAE3000788F2 /* FBWebServerParams.m in Sources */ = {isa = PBXBuildFile; fileRef = 718D2C112C60BAE3000788F2 /* FBWebServerParams.m */; }; 718F49C8230844330045FE8B /* FBProtocolHelpersTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 718F49C7230844330045FE8B /* FBProtocolHelpersTests.m */; }; 718F49C923087ACF0045FE8B /* FBProtocolHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 71B155DD23080CA600646AFB /* FBProtocolHelpers.h */; }; 718F49CA23087AD30045FE8B /* FBProtocolHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = 71B155DE23080CA600646AFB /* FBProtocolHelpers.m */; }; @@ -1027,6 +1031,8 @@ 718226C72587443600661B83 /* GCDAsyncSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GCDAsyncSocket.h; path = WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncSocket.h; sourceTree = SOURCE_ROOT; }; 718226C82587443600661B83 /* GCDAsyncSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GCDAsyncSocket.m; path = WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncSocket.m; sourceTree = SOURCE_ROOT; }; 718226C92587443600661B83 /* GCDAsyncUdpSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GCDAsyncUdpSocket.m; path = WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncUdpSocket.m; sourceTree = SOURCE_ROOT; }; + 718D2C102C60BAE3000788F2 /* FBWebServerParams.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FBWebServerParams.h; sourceTree = ""; }; + 718D2C112C60BAE3000788F2 /* FBWebServerParams.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBWebServerParams.m; sourceTree = ""; }; 718F49C7230844330045FE8B /* FBProtocolHelpersTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBProtocolHelpersTests.m; sourceTree = ""; }; 71930C4020662E1F00D3AFEC /* FBPasteboard.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FBPasteboard.h; sourceTree = ""; }; 71930C4120662E1F00D3AFEC /* FBPasteboard.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBPasteboard.m; sourceTree = ""; }; @@ -1948,6 +1954,8 @@ 7140974A1FAE1B51008FB2C5 /* FBW3CActionsSynthesizer.m */, 713AE573243A53BE0000D657 /* FBW3CActionsHelpers.h */, 713AE574243A53BE0000D657 /* FBW3CActionsHelpers.m */, + 718D2C102C60BAE3000788F2 /* FBWebServerParams.h */, + 718D2C112C60BAE3000788F2 /* FBWebServerParams.m */, 7157B28F221DADD2001C348C /* FBXCAXClientProxy.h */, 7157B290221DADD2001C348C /* FBXCAXClientProxy.m */, EE5A24401F136C8D0078B1D9 /* FBXCodeCompatibility.h */, @@ -2463,6 +2471,7 @@ 641EE6D62240C5CA00173FCB /* FBLogger.h in Headers */, 71BB58F72B96531900CB9BFE /* FBScreenRecordingContainer.h in Headers */, 641EE6D72240C5CA00173FCB /* XCTestObserver.h in Headers */, + 718D2C142C60BAE3000788F2 /* FBWebServerParams.h in Headers */, 641EE6D82240C5CA00173FCB /* XCUIElement.h in Headers */, 641EE6D92240C5CA00173FCB /* XCKeyboardInputSolver.h in Headers */, 718226CB2587443700661B83 /* GCDAsyncUdpSocket.h in Headers */, @@ -2718,6 +2727,7 @@ EE35AD311E3B77D600A02D78 /* XCKeyboardLayout.h in Headers */, 716C9DFA27315D21005AD475 /* FBReflectionUtils.h in Headers */, E444DCB624913C220060D7EB /* RouteRequest.h in Headers */, + 718D2C132C60BAE3000788F2 /* FBWebServerParams.h in Headers */, 71F5BE23252E576C00EE9EBA /* XCUIElement+FBSwiping.h in Headers */, 718226CC2587443700661B83 /* GCDAsyncSocket.h in Headers */, EE35AD3B1E3B77D600A02D78 /* XCTAsyncActivity-Protocol.h in Headers */, @@ -3093,6 +3103,7 @@ 641EE5D72240C5CA00173FCB /* FBScreenshotCommands.m in Sources */, 71F3E7D725417FF400E0C22B /* FBSettings.m in Sources */, 641EE5D92240C5CA00173FCB /* XCUIElement+FBPickerWheel.m in Sources */, + 718D2C152C60BAE3000788F2 /* FBWebServerParams.m in Sources */, 641EE5DA2240C5CA00173FCB /* XCUIApplicationProcessDelay.m in Sources */, 641EE5DB2240C5CA00173FCB /* FBXPath.m in Sources */, 71C8E55425399A6B008572C1 /* XCUIApplication+FBQuiescence.m in Sources */, @@ -3282,6 +3293,7 @@ AD76723E1D6B7CC000610457 /* XCUIElement+FBTyping.m in Sources */, EE158AAF1CBD456F00A3E3F0 /* XCUIElement+FBAccessibility.m in Sources */, 714E14BA29805CAE00375DD7 /* XCAXClient_iOS+FBSnapshotReqParams.m in Sources */, + 718D2C122C60BAE3000788F2 /* FBWebServerParams.m in Sources */, 7150348821A6DAD600A0F4BA /* FBImageUtils.m in Sources */, E444DCAB24913C220060D7EB /* HTTPResponseProxy.m in Sources */, E444DC6D249131890060D7EB /* HTTPErrorResponse.m in Sources */, diff --git a/WebDriverAgentLib/Commands/FBSessionCommands.m b/WebDriverAgentLib/Commands/FBSessionCommands.m index 7b3c4dbb5..97baab7a1 100644 --- a/WebDriverAgentLib/Commands/FBSessionCommands.m +++ b/WebDriverAgentLib/Commands/FBSessionCommands.m @@ -20,6 +20,7 @@ #import "FBRuntimeUtils.h" #import "FBActiveAppDetectionPoint.h" #import "FBXCodeCompatibility.h" +#import "FBWebServerParams.h" #import "XCUIApplication+FBHelpers.h" #import "XCUIApplication+FBQuiescence.h" #import "XCUIDevice.h" @@ -176,6 +177,18 @@ + (NSArray *)routes _XCTSetApplicationStateTimeout(defaultTimeout); } } + if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"17.0") && [bundleID isEqualToString:FB_SAFARI_BUNDLE_ID]) { + // Opening the default URL in Safari instead of an empty page helps + // the remote debugger to avoid issues while looking for active web views + FBWebServerParams *wsParams = FBWebServerParams.sharedInstance; + NSString *healthEndpoint = [NSString stringWithFormat:@"http://127.0.0.1:%@/health", wsParams.port]; + id errorResponse = [self openDeepLink:healthEndpoint + withApplication:bundleID + timeout:capabilities[FB_CAP_APP_LAUNCH_STATE_TIMEOUT_SEC]]; + if (nil != errorResponse) { + NSLog(@"Was not able to open the default URL %@ in Safari", healthEndpoint); + } + } } if (!app.running) { NSString *errorMsg = [NSString stringWithFormat:@"Cannot launch %@ application. Make sure the correct bundle identifier has been provided in capabilities and check the device log for possible crash report occurrences", bundleID]; diff --git a/WebDriverAgentLib/Routing/FBSession.h b/WebDriverAgentLib/Routing/FBSession.h index 9b73d4d16..b617ae096 100644 --- a/WebDriverAgentLib/Routing/FBSession.h +++ b/WebDriverAgentLib/Routing/FBSession.h @@ -14,6 +14,9 @@ NS_ASSUME_NONNULL_BEGIN +/** Bundle identifier of Mobile Safari browser */ +extern NSString* const FB_SAFARI_BUNDLE_ID; + /** Class that represents testing session */ diff --git a/WebDriverAgentLib/Routing/FBSession.m b/WebDriverAgentLib/Routing/FBSession.m index 2b1753cd2..14565ad00 100644 --- a/WebDriverAgentLib/Routing/FBSession.m +++ b/WebDriverAgentLib/Routing/FBSession.m @@ -33,6 +33,8 @@ */ NSString *const FBDefaultApplicationAuto = @"auto"; +NSString *const FB_SAFARI_BUNDLE_ID = @"com.apple.mobilesafari"; + @interface FBSession () @property (nullable, nonatomic) XCUIApplication *testedApplication; @property (nonatomic) BOOL isTestedApplicationExpectedToRun; diff --git a/WebDriverAgentLib/Routing/FBWebServer.m b/WebDriverAgentLib/Routing/FBWebServer.m index ff9e4c424..8d9c30203 100644 --- a/WebDriverAgentLib/Routing/FBWebServer.m +++ b/WebDriverAgentLib/Routing/FBWebServer.m @@ -23,6 +23,7 @@ #import "FBUnknownCommands.h" #import "FBConfiguration.h" #import "FBLogger.h" +#import "FBWebServerParams.h" #import "XCUIDevice+FBHelpers.h" @@ -102,6 +103,8 @@ - (void)startHTTPServer serverStarted = [self attemptToStartServer:self.server onPort:port withError:&error]; if (serverStarted) { + FBWebServerParams* wsParams = FBWebServerParams.sharedInstance; + wsParams.port = @(self.server.port); break; } diff --git a/WebDriverAgentLib/Utilities/FBWebServerParams.h b/WebDriverAgentLib/Utilities/FBWebServerParams.h new file mode 100644 index 000000000..c92daecb2 --- /dev/null +++ b/WebDriverAgentLib/Utilities/FBWebServerParams.h @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface FBWebServerParams : NSObject + +/** The local port number WDA server is running on */ +@property (nonatomic, nullable) NSNumber *port; + ++ (id)sharedInstance; + +@end + +NS_ASSUME_NONNULL_END diff --git a/WebDriverAgentLib/Utilities/FBWebServerParams.m b/WebDriverAgentLib/Utilities/FBWebServerParams.m new file mode 100644 index 000000000..65e85f65a --- /dev/null +++ b/WebDriverAgentLib/Utilities/FBWebServerParams.m @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "FBWebServerParams.h" + +@implementation FBWebServerParams + ++ (instancetype)sharedInstance +{ + static FBWebServerParams *instance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + instance = [[self alloc] init]; + }); + return instance; +} + +@end diff --git a/WebDriverAgentTests/IntegrationTests/FBSafariAlertTests.m b/WebDriverAgentTests/IntegrationTests/FBSafariAlertTests.m index 73e2de337..5b49b35d9 100644 --- a/WebDriverAgentTests/IntegrationTests/FBSafariAlertTests.m +++ b/WebDriverAgentTests/IntegrationTests/FBSafariAlertTests.m @@ -25,15 +25,13 @@ @interface FBSafariAlertIntegrationTests : FBIntegrationTestCase @end -static NSString *const SAFARI_BUNDLE_ID = @"com.apple.mobilesafari"; - @implementation FBSafariAlertIntegrationTests - (void)setUp { [super setUp]; self.session = [FBSession initWithApplication:XCUIApplication.fb_activeApplication]; - [self.session launchApplicationWithBundleId:SAFARI_BUNDLE_ID + [self.session launchApplicationWithBundleId:FB_SAFARI_BUNDLE_ID shouldWaitForQuiescence:nil arguments:nil environment:nil]; @@ -42,7 +40,7 @@ - (void)setUp - (void)tearDown { - [self.session terminateApplicationWithBundleId:SAFARI_BUNDLE_ID]; + [self.session terminateApplicationWithBundleId:FB_SAFARI_BUNDLE_ID]; } - (void)disabled_testCanHandleSafariInputPrompt From 742bf90dec2456153ec0a90d5150a4c4ec4cb07b Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Mon, 5 Aug 2024 13:48:29 +0200 Subject: [PATCH 2/6] Preboot simulator --- .github/workflows/functional-test.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/functional-test.yml b/.github/workflows/functional-test.yml index 90bacdc9a..cf951a0ad 100644 --- a/.github/workflows/functional-test.yml +++ b/.github/workflows/functional-test.yml @@ -34,15 +34,15 @@ jobs: mkdir -p ./Resources/WebDriverAgent.bundle name: Install dev dependencies - - uses: futureware-tech/simulator-action@v3 - with: - model: ${{matrix.test_targets.IOS_MODEL}} - os: iOS - os_version: ${{matrix.test_targets.IOS_VERSION}} - erase_before_boot: true - # to prevent unexpected shutdown failure error - shutdown_after_job: false - name: Preboot Simulator + - name: Prepare iOS simulator + env: + DEVICE_NAME: ${{matrix.test_targets.IOS_MODEL}} + PLATFORM_VERSION: ${{matrix.test_targets.IOS_VERSION}} + run: | + open -Fn "$(xcode-select -p)/Applications/Simulator.app" + udid=$(xcrun simctl list devices available -j | \ + node -p "Object.entries(JSON.parse(fs.readFileSync(0)).devices).filter((x) => x[0].includes('$PLATFORM_VERSION'.replace('.', '-'))).reduce((acc, x) => [...acc, ...x[1]], []).find(({name}) => name === '$DEVICE_NAME').udid") + xcrun simctl bootstatus $udid -b - run: npm run e2e-test name: Run functional tests From 7f9a89b4835cf90c95352eefffb601b8e1370590 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Mon, 5 Aug 2024 14:35:30 +0200 Subject: [PATCH 3/6] moar --- .github/workflows/functional-test.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/functional-test.yml b/.github/workflows/functional-test.yml index cf951a0ad..7ed83317e 100644 --- a/.github/workflows/functional-test.yml +++ b/.github/workflows/functional-test.yml @@ -12,11 +12,11 @@ jobs: fail-fast: false matrix: test_targets: - - XCODE_VERSION: 15.3 - IOS_VERSION: 17.4 + - XCODE_VERSION: '15.3' + IOS_VERSION: '17.4' IOS_MODEL: iPhone 15 Plus - XCODE_VERSION: 14.3.1 - IOS_VERSION: 16.4 + IOS_VERSION: '16.4' IOS_MODEL: iPhone 14 Plus # https://github.com/actions/runner-images/blob/main/images/macos/macos-14-Readme.md @@ -43,6 +43,7 @@ jobs: udid=$(xcrun simctl list devices available -j | \ node -p "Object.entries(JSON.parse(fs.readFileSync(0)).devices).filter((x) => x[0].includes('$PLATFORM_VERSION'.replace('.', '-'))).reduce((acc, x) => [...acc, ...x[1]], []).find(({name}) => name === '$DEVICE_NAME').udid") xcrun simctl bootstatus $udid -b + xcrun simctl shutdown $udid - run: npm run e2e-test name: Run functional tests From 39dce1960306b9062bf96dae2b2d23b2a97e6a82 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Mon, 5 Aug 2024 15:26:24 +0200 Subject: [PATCH 4/6] Bump timeout --- test/functional/webdriveragent-e2e-specs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/webdriveragent-e2e-specs.js b/test/functional/webdriveragent-e2e-specs.js index 1a1a4324f..2f0ddc323 100644 --- a/test/functional/webdriveragent-e2e-specs.js +++ b/test/functional/webdriveragent-e2e-specs.js @@ -23,7 +23,7 @@ function getStartOpts (device) { port: 8100, realDevice: false, showXcodeLog: true, - wdaLaunchTimeout: 60 * 3 * 1000, + wdaLaunchTimeout: 60 * 4 * 1000, }; } From 7957029ce58dafe1dbcdcb02c50d5b1326ce043b Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Mon, 5 Aug 2024 16:13:59 +0200 Subject: [PATCH 5/6] prebuild --- .github/workflows/functional-test.yml | 1 + test/functional/webdriveragent-e2e-specs.js | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/functional-test.yml b/.github/workflows/functional-test.yml index 7ed83317e..e9bb01e19 100644 --- a/.github/workflows/functional-test.yml +++ b/.github/workflows/functional-test.yml @@ -50,5 +50,6 @@ jobs: env: CI: true _FORCE_LOGS: 1 + _LOG_TIMESTAMP: 1 DEVICE_NAME: ${{matrix.test_targets.IOS_MODEL}} PLATFORM_VERSION: ${{matrix.test_targets.IOS_VERSION}} diff --git a/test/functional/webdriveragent-e2e-specs.js b/test/functional/webdriveragent-e2e-specs.js index 2f0ddc323..8638a6dde 100644 --- a/test/functional/webdriveragent-e2e-specs.js +++ b/test/functional/webdriveragent-e2e-specs.js @@ -23,7 +23,7 @@ function getStartOpts (device) { port: 8100, realDevice: false, showXcodeLog: true, - wdaLaunchTimeout: 60 * 4 * 1000, + wdaLaunchTimeout: 60 * 3 * 1000, }; } @@ -59,6 +59,15 @@ describe('WebDriverAgent', function () { PLATFORM_VERSION ); device = await getSimulator(simctl.udid); + + // Prebuild WDA + const wda = new WebDriverAgent(xcodeVersion, { + iosSdkVersion: PLATFORM_VERSION, + platformVersion: PLATFORM_VERSION, + showXcodeLog: true, + device, + }); + await wda.xcodebuild.start(true); }); after(async function () { From 653a4a9a2ba0d5826b9174aea529705052e40556 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Mon, 5 Aug 2024 16:31:51 +0200 Subject: [PATCH 6/6] Bump timeout --- test/functional/webdriveragent-e2e-specs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/webdriveragent-e2e-specs.js b/test/functional/webdriveragent-e2e-specs.js index 8638a6dde..3cf2862f1 100644 --- a/test/functional/webdriveragent-e2e-specs.js +++ b/test/functional/webdriveragent-e2e-specs.js @@ -8,7 +8,7 @@ import { retryInterval } from 'asyncbox'; import { WebDriverAgent } from '../../lib/webdriveragent'; import axios from 'axios'; -const MOCHA_TIMEOUT_MS = 60 * 1000 * 4; +const MOCHA_TIMEOUT_MS = 60 * 1000 * 5; const SIM_DEVICE_NAME = 'webDriverAgentTest'; const SIM_STARTUP_TIMEOUT_MS = MOCHA_TIMEOUT_MS;