appium-webdriveragent 16.2.2 → 16.3.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 (64) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/PrivateHeaders/XCTest/XCSynthesizedEventRecord.h +3 -3
  3. package/PrivateHeaders/XCTest/XCUIApplication.h +1 -1
  4. package/PrivateHeaders/XCTest/XCUIElement.h +1 -1
  5. package/Scripts/build.sh +6 -0
  6. package/WebDriverAgent.xcodeproj/project.pbxproj +1482 -2
  7. package/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/IntegrationApp_watchOS.xcscheme +76 -0
  8. package/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/IntegrationTests_watchOS.xcscheme +86 -0
  9. package/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/WebDriverAgentLib_watchOS.xcscheme +85 -0
  10. package/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/WebDriverAgentRunner.xcscheme +1 -1
  11. package/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/WebDriverAgentRunner_watchOS.xcscheme +128 -0
  12. package/WebDriverAgentLib/Categories/XCUIApplication+FBAlert.m +5 -0
  13. package/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m +2 -0
  14. package/WebDriverAgentLib/Categories/XCUIApplication+FBTouchAction.m +1 -1
  15. package/WebDriverAgentLib/Categories/XCUIDevice+FBHelpers.m +4 -4
  16. package/WebDriverAgentLib/Categories/XCUIDevice+FBRotation.h +1 -1
  17. package/WebDriverAgentLib/Categories/XCUIDevice+FBRotation.m +1 -1
  18. package/WebDriverAgentLib/Categories/XCUIElement+FBPickerWheel.m +1 -1
  19. package/WebDriverAgentLib/Categories/XCUIElement+FBTyping.m +11 -0
  20. package/WebDriverAgentLib/Commands/FBCustomCommands.m +19 -4
  21. package/WebDriverAgentLib/Commands/FBElementCommands.m +6 -5
  22. package/WebDriverAgentLib/Commands/FBOrientationCommands.m +1 -1
  23. package/WebDriverAgentLib/Commands/FBSessionCommands.m +29 -5
  24. package/WebDriverAgentLib/Info.plist +2 -2
  25. package/WebDriverAgentLib/Routing/FBTCPSocket.h +70 -0
  26. package/WebDriverAgentLib/Routing/FBTCPSocket.m +199 -0
  27. package/WebDriverAgentLib/Routing/FBWebServer.m +33 -3
  28. package/WebDriverAgentLib/Routing/WatchOS/FBWatchHTTPServer.h +68 -0
  29. package/WebDriverAgentLib/Routing/WatchOS/FBWatchHTTPServer.m +376 -0
  30. package/WebDriverAgentLib/Routing/WatchOS/RouteRequest.h +30 -0
  31. package/WebDriverAgentLib/Routing/WatchOS/RouteRequest.m +25 -0
  32. package/WebDriverAgentLib/Routing/WatchOS/RouteResponse.h +30 -0
  33. package/WebDriverAgentLib/Routing/WatchOS/RouteResponse.m +54 -0
  34. package/WebDriverAgentLib/Utilities/FBActiveAppDetectionPoint.m +8 -0
  35. package/WebDriverAgentLib/Utilities/FBBaseActionsSynthesizer.h +1 -1
  36. package/WebDriverAgentLib/Utilities/FBBaseActionsSynthesizer.m +1 -1
  37. package/WebDriverAgentLib/Utilities/FBConfiguration.h +1 -1
  38. package/WebDriverAgentLib/Utilities/FBConfiguration.m +3 -3
  39. package/WebDriverAgentLib/Utilities/FBImageProcessor.m +7 -2
  40. package/WebDriverAgentLib/Utilities/FBMacros.h +14 -5
  41. package/WebDriverAgentLib/Utilities/FBMathUtils.h +1 -1
  42. package/WebDriverAgentLib/Utilities/FBMathUtils.m +1 -1
  43. package/WebDriverAgentLib/Utilities/FBPasteboard.h +1 -1
  44. package/WebDriverAgentLib/Utilities/FBPasteboard.m +1 -1
  45. package/WebDriverAgentLib/Utilities/FBSettingsHandler.m +2 -2
  46. package/WebDriverAgentLib/Utilities/FBW3CActionsSynthesizer.h +1 -1
  47. package/WebDriverAgentLib/Utilities/FBW3CActionsSynthesizer.m +1 -1
  48. package/WebDriverAgentTests/IntegrationApp_watchOS/ContentView.swift +31 -0
  49. package/WebDriverAgentTests/IntegrationApp_watchOS/WatchSpikeApp.swift +18 -0
  50. package/WebDriverAgentTests/IntegrationTests/FBForceTouchTests.m +3 -0
  51. package/WebDriverAgentTests/IntegrationTests/FBPasteboardTests.m +3 -2
  52. package/WebDriverAgentTests/IntegrationTests_watchOS/WDAAlertIntegrationTests.swift +23 -0
  53. package/WebDriverAgentTests/IntegrationTests_watchOS/WDAAppLifecycleIntegrationTests.swift +57 -0
  54. package/WebDriverAgentTests/IntegrationTests_watchOS/WDAClickIntegrationTests.swift +31 -0
  55. package/WebDriverAgentTests/IntegrationTests_watchOS/WDADeviceIntegrationTests.swift +50 -0
  56. package/WebDriverAgentTests/IntegrationTests_watchOS/WDAElementAttributeIntegrationTests.swift +57 -0
  57. package/WebDriverAgentTests/IntegrationTests_watchOS/WDAFindIntegrationTests.swift +126 -0
  58. package/WebDriverAgentTests/IntegrationTests_watchOS/WDAScreenshotAndSourceIntegrationTests.swift +52 -0
  59. package/WebDriverAgentTests/IntegrationTests_watchOS/WDASessionIntegrationTests.swift +72 -0
  60. package/WebDriverAgentTests/IntegrationTests_watchOS/WDATypingIntegrationTests.swift +57 -0
  61. package/WebDriverAgentTests/IntegrationTests_watchOS/WDAUnknownCommandIntegrationTests.swift +24 -0
  62. package/WebDriverAgentTests/IntegrationTests_watchOS/WDAWatchHTTPClient.swift +95 -0
  63. package/WebDriverAgentTests/IntegrationTests_watchOS/WDAWatchIntegrationTestCase.swift +61 -0
  64. package/package.json +1 -1
@@ -0,0 +1,57 @@
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.
7
+ */
8
+
9
+ import XCTest
10
+
11
+ /// Covers /element/:uuid/value, /element/:uuid/clear, and /wda/keyboard/dismiss.
12
+ ///
13
+ /// KNOWN LIMITATION (see XCUIElement+FBTyping.m): the keyboard opens and the field gets focus,
14
+ /// but no keystrokes land. Wrapped in XCTExpectFailure so this re-verifies itself and starts
15
+ /// failing loudly the moment it starts working, instead of silently staying stale.
16
+ final class WDATypingIntegrationTests: WDAWatchIntegrationTestCase {
17
+ func testSetValueOpensTheKeyboardAndAttemptsToTypeIntoTheField() throws {
18
+ let fieldId = try findElement(byAccessibilityId: "typingField")
19
+ XCTAssertEqual(try attributeValue(fieldId, "value"), "Type here", "expected the untouched placeholder")
20
+
21
+ let setValueResponse = try client.post("/session/\(sessionId!)/element/\(fieldId)/value", body: [
22
+ "value": ["h", "i"]
23
+ ])
24
+ XCTAssertEqual(setValueResponse.statusCode, 200, "the route itself should not error even though typing doesn't land")
25
+
26
+ XCTExpectFailure("watchOS keystroke delivery into the on-screen keyboard is a known unresolved limitation") {
27
+ let value = try? attributeValue(fieldId, "value")
28
+ XCTAssertEqual(value, "hi")
29
+ }
30
+
31
+ // Back out so later tests start clean.
32
+ if let cancelId = try? findElement(byAccessibilityId: "Cancel") {
33
+ _ = try? client.post("/session/\(sessionId!)/element/\(cancelId)/click")
34
+ }
35
+ }
36
+
37
+ func testClearingAnAlreadyEmptyFieldSucceeds() throws {
38
+ // Clearing an empty field short-circuits, so this works despite the typing limitation.
39
+ let fieldId = try findElement(byAccessibilityId: "typingField")
40
+ let clearResponse = try client.post("/session/\(sessionId!)/element/\(fieldId)/clear")
41
+ XCTAssertEqual(clearResponse.statusCode, 200)
42
+ }
43
+
44
+ func testDismissKeyboardRouteRespondsWithoutCrashingTheServer() throws {
45
+ // Only asserts the route round-trips cleanly, not that dismissal actually happens.
46
+ let fieldId = try findElement(byAccessibilityId: "typingField")
47
+ try client.post("/session/\(sessionId!)/element/\(fieldId)/click")
48
+ Thread.sleep(forTimeInterval: 1)
49
+
50
+ _ = try client.post("/session/\(sessionId!)/wda/keyboard/dismiss")
51
+
52
+ // Back out regardless of whether dismiss actually closed the sheet.
53
+ if let cancelId = try? findElement(byAccessibilityId: "Cancel") {
54
+ _ = try? client.post("/session/\(sessionId!)/element/\(cancelId)/click")
55
+ }
56
+ }
57
+ }
@@ -0,0 +1,24 @@
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.
7
+ */
8
+
9
+ import XCTest
10
+
11
+ /// Covers the catch-all 404 routes and the OPTIONS ping route - neither needs a session.
12
+ final class WDAUnknownCommandIntegrationTests: XCTestCase {
13
+ let client = WDAWatchHTTPClient()
14
+
15
+ func testUnknownRouteReturnsAnError() throws {
16
+ let response = try client.get("/this/route/does/not/exist")
17
+ XCTAssertNotEqual(response.statusCode, 200)
18
+ }
19
+
20
+ func testPing() throws {
21
+ let response = try client.send("OPTIONS", "/anything")
22
+ XCTAssertEqual(response.statusCode, 200)
23
+ }
24
+ }
@@ -0,0 +1,95 @@
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.
7
+ */
8
+
9
+ import Foundation
10
+
11
+ /// Minimal synchronous JSON/HTTP client for driving the real WebDriverAgentRunner_watchOS
12
+ /// server, the same way a real client (Appium, curl) would. Requires the server to already be
13
+ /// running, e.g. via `xcodebuild test -scheme WebDriverAgentRunner_watchOS`.
14
+ struct WDAWatchHTTPClient {
15
+ struct Response {
16
+ let statusCode: Int
17
+ let json: [String: Any]?
18
+
19
+ var value: Any? { json?["value"] }
20
+ var valueDict: [String: Any]? { value as? [String: Any] }
21
+ var valueString: String? { value as? String }
22
+ }
23
+
24
+ enum ClientError: Error, CustomStringConvertible {
25
+ case requestFailed(String)
26
+
27
+ var description: String {
28
+ switch self {
29
+ case .requestFailed(let message): return message
30
+ }
31
+ }
32
+ }
33
+
34
+ let baseURL: URL
35
+
36
+ init() {
37
+ let host = ProcessInfo.processInfo.environment["WDA_TEST_HOST"] ?? "127.0.0.1"
38
+ let port = ProcessInfo.processInfo.environment["WDA_TEST_PORT"] ?? "8100"
39
+ self.baseURL = URL(string: "http://\(host):\(port)")!
40
+ }
41
+
42
+ /// Splits path/query before resolving against baseURL - appendingPathComponent would
43
+ /// percent-encode a literal "?" instead of treating it as a query delimiter.
44
+ private func url(for path: String) -> URL {
45
+ let parts = path.split(separator: "?", maxSplits: 1)
46
+ var components = URLComponents(url: baseURL, resolvingAgainstBaseURL: false)!
47
+ components.path = components.path + parts[0]
48
+ if parts.count > 1 {
49
+ components.percentEncodedQuery = String(parts[1])
50
+ }
51
+ return components.url!
52
+ }
53
+
54
+ @discardableResult
55
+ func send(_ method: String, _ path: String, body: [String: Any]? = nil, timeout: TimeInterval = 20) throws -> Response {
56
+ var request = URLRequest(url: url(for: path))
57
+ request.httpMethod = method
58
+ request.timeoutInterval = timeout
59
+ if let body = body {
60
+ request.setValue("application/json", forHTTPHeaderField: "Content-Type")
61
+ request.httpBody = try JSONSerialization.data(withJSONObject: body)
62
+ }
63
+
64
+ let semaphore = DispatchSemaphore(value: 0)
65
+ var resultData: Data?
66
+ var resultResponse: URLResponse?
67
+ var resultError: Error?
68
+
69
+ URLSession.shared.dataTask(with: request) { data, response, error in
70
+ resultData = data
71
+ resultResponse = response
72
+ resultError = error
73
+ semaphore.signal()
74
+ }.resume()
75
+
76
+ if semaphore.wait(timeout: .now() + timeout + 5) == .timedOut {
77
+ throw ClientError.requestFailed("Request to \(method) \(path) timed out")
78
+ }
79
+ if let resultError = resultError {
80
+ throw ClientError.requestFailed("Request to \(method) \(path) failed: \(resultError)")
81
+ }
82
+ guard let httpResponse = resultResponse as? HTTPURLResponse else {
83
+ throw ClientError.requestFailed("Request to \(method) \(path) returned no HTTP response")
84
+ }
85
+ var json: [String: Any]?
86
+ if let resultData = resultData, !resultData.isEmpty {
87
+ json = try? JSONSerialization.jsonObject(with: resultData) as? [String: Any]
88
+ }
89
+ return Response(statusCode: httpResponse.statusCode, json: json)
90
+ }
91
+
92
+ func get(_ path: String) throws -> Response { try send("GET", path) }
93
+ func post(_ path: String, body: [String: Any] = [:]) throws -> Response { try send("POST", path, body: body) }
94
+ func delete(_ path: String) throws -> Response { try send("DELETE", path) }
95
+ }
@@ -0,0 +1,61 @@
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.
7
+ */
8
+
9
+ import XCTest
10
+
11
+ /// Creates a fresh WDA session against IntegrationApp_watchOS per test, so each starts clean.
12
+ class WDAWatchIntegrationTestCase: XCTestCase {
13
+ static let integrationAppBundleId = ProcessInfo.processInfo.environment["WDA_TEST_BUNDLE_ID"]
14
+ ?? "com.facebook.wda.IntegrationApp.watchOS"
15
+
16
+ let client = WDAWatchHTTPClient()
17
+ var sessionId: String!
18
+
19
+ override func setUp() {
20
+ super.setUp()
21
+ continueAfterFailure = false
22
+ do {
23
+ let response = try client.post("/session", body: [
24
+ "capabilities": ["alwaysMatch": ["bundleId": Self.integrationAppBundleId]]
25
+ ])
26
+ guard response.statusCode == 200, let sessionId = response.valueDict?["sessionId"] as? String else {
27
+ XCTFail("Failed to create session: \(String(describing: response.json))")
28
+ return
29
+ }
30
+ self.sessionId = sessionId
31
+ } catch {
32
+ XCTFail("Failed to create session: \(error)")
33
+ }
34
+ }
35
+
36
+ override func tearDown() {
37
+ if let sessionId = sessionId {
38
+ _ = try? client.delete("/session/\(sessionId)")
39
+ }
40
+ super.tearDown()
41
+ }
42
+
43
+ /// Finds an element by accessibility id and returns its WDA element UUID.
44
+ @discardableResult
45
+ func findElement(byAccessibilityId accessibilityId: String, file: StaticString = #filePath, line: UInt = #line) throws -> String {
46
+ let response = try client.post("/session/\(sessionId!)/element", body: [
47
+ "using": "accessibility id",
48
+ "value": accessibilityId,
49
+ ])
50
+ guard response.statusCode == 200, let elementId = response.valueDict?["ELEMENT"] as? String else {
51
+ XCTFail("Could not find element '\(accessibilityId)': \(String(describing: response.json))", file: file, line: line)
52
+ throw WDAWatchHTTPClient.ClientError.requestFailed("element not found")
53
+ }
54
+ return elementId
55
+ }
56
+
57
+ func attributeValue(_ elementId: String, _ name: String) throws -> String? {
58
+ let response = try client.get("/session/\(sessionId!)/element/\(elementId)/attribute/\(name)")
59
+ return response.valueString
60
+ }
61
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appium-webdriveragent",
3
- "version": "16.2.2",
3
+ "version": "16.3.0",
4
4
  "description": "Package bundling WebDriverAgent",
5
5
  "keywords": [
6
6
  "Appium",