diff --git a/.github/workflows/functional-test.yml b/.github/workflows/functional-test.yml index 90bacdc9a..e9bb01e19 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 @@ -34,20 +34,22 @@ 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 + xcrun simctl shutdown $udid - run: npm run e2e-test name: Run functional tests 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/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 diff --git a/test/functional/webdriveragent-e2e-specs.js b/test/functional/webdriveragent-e2e-specs.js index 1a1a4324f..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; @@ -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 () {