From 7fa3ea7578be3c8e4392d35620aeda65723727f2 Mon Sep 17 00:00:00 2001 From: Tristan Labelle Date: Tue, 29 Apr 2025 10:39:36 -0500 Subject: [PATCH 1/6] Implement protocol detection and protocol-agnostic session creation. --- Sources/WebDriver/HTTPWebDriver.swift | 38 ++++++++++++++++--- Sources/WebDriver/Requests.swift | 9 ++++- Sources/WebDriver/Session.swift | 27 +++++++++++-- Sources/WebDriver/WebDriver.swift | 11 ++++-- Tests/AppiumTests/AppiumTests.swift | 4 +- .../UnitTests/APIToRequestMappingTests.swift | 24 +++++++++++- Tests/WinAppDriverTests/MSInfo32App.swift | 2 +- Tests/WinAppDriverTests/TimeoutTests.swift | 2 +- 8 files changed, 99 insertions(+), 18 deletions(-) diff --git a/Sources/WebDriver/HTTPWebDriver.swift b/Sources/WebDriver/HTTPWebDriver.swift index 6234e26..265992d 100644 --- a/Sources/WebDriver/HTTPWebDriver.swift +++ b/Sources/WebDriver/HTTPWebDriver.swift @@ -3,32 +3,60 @@ import Foundation import FoundationNetworking #endif +/// Thrown if we fail to detect the protocol a webdriver server uses. +public struct ProtocolDetectionError: Error {} + /// A connection to a WebDriver server over HTTP. public struct HTTPWebDriver: WebDriver { - let rootURL: URL + private let serverURL: URL public let wireProtocol: WireProtocol public static let defaultRequestTimeout: TimeInterval = 5 // seconds public init(endpoint: URL, wireProtocol: WireProtocol) { - rootURL = endpoint + serverURL = endpoint self.wireProtocol = wireProtocol } + public static func createWithDetectedProtocol(serverURL: URL) throws -> HTTPWebDriver { + .init(endpoint: serverURL, wireProtocol: try detectProtocol(serverURL: serverURL)) + } + + public static func detectProtocol(serverURL: URL) throws -> WireProtocol { + // The status request is the same for the Selenium Legacy JSON protocol and W3C, + // but the response format is different. + let urlRequest = try Self.buildURLRequest(serverURL: serverURL, Requests.Status_Legacy()) + + // Send the request and decode result or error + let (status, responseData) = try urlRequest.send() + guard status == 200 else { + throw try JSONDecoder().decode(ErrorResponse.self, from: responseData) + } + + if let _ = try? JSONDecoder().decode(Requests.Status_Legacy.Response.self, from: responseData) { + return .legacySelenium + } else if let _ = try? JSONDecoder().decode(Requests.Status_W3C.Response.self, from: responseData) { + return .w3c + } else { + throw ProtocolDetectionError() + } + } + @discardableResult public func send(_ request: Req) throws -> Req.Response { - let urlRequest = try buildURLRequest(request) + let urlRequest = try Self.buildURLRequest(serverURL: self.serverURL, request) // Send the request and decode result or error let (status, responseData) = try urlRequest.send() guard status == 200 else { throw try JSONDecoder().decode(ErrorResponse.self, from: responseData) } + return try JSONDecoder().decode(Req.Response.self, from: responseData) } - private func buildURLRequest(_ request: Req) throws -> URLRequest { - var url = rootURL + private static func buildURLRequest(serverURL: URL, _ request: Req) throws -> URLRequest { + var url = serverURL for (index, pathComponent) in request.pathComponents.enumerated() { let last = index == request.pathComponents.count - 1 url.appendPathComponent(pathComponent, isDirectory: !last) diff --git a/Sources/WebDriver/Requests.swift b/Sources/WebDriver/Requests.swift index 892d20c..aab3295 100644 --- a/Sources/WebDriver/Requests.swift +++ b/Sources/WebDriver/Requests.swift @@ -663,12 +663,19 @@ public enum Requests { } // https://www.selenium.dev/documentation/legacy/json_wire_protocol/#status - public struct Status: Request { + public struct Status_Legacy: Request { public var pathComponents: [String] { ["status"] } public var method: HTTPMethod { .get } public typealias Response = WebDriverStatus } + + public struct Status_W3C: Request { + public var pathComponents: [String] { ["status"] } + public var method: HTTPMethod { .get } + + public typealias Response = ResponseWithValue + } // https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidorientation public enum SessionOrientation { diff --git a/Sources/WebDriver/Session.swift b/Sources/WebDriver/Session.swift index b33bcbe..8bbc219 100644 --- a/Sources/WebDriver/Session.swift +++ b/Sources/WebDriver/Session.swift @@ -2,7 +2,7 @@ import Foundation /// Represents a session in the WebDriver protocol, /// which manages the lifetime of a page or app under UI automation. -public class Session { +public final class Session { public let webDriver: any WebDriver public let id: String public let capabilities: Capabilities @@ -20,7 +20,8 @@ public class Session { self.shouldDelete = owned } - public convenience init(webDriver: any WebDriver, desiredCapabilities: Capabilities, requiredCapabilities: Capabilities? = nil) throws { + /// Initializer for Legacy Selenium JSON Protocol + private convenience init(webDriver: any WebDriver, desiredCapabilities: Capabilities, requiredCapabilities: Capabilities?) throws { let response = try webDriver.send(Requests.Session_Legacy( desiredCapabilities: desiredCapabilities, requiredCapabilities: requiredCapabilities)) self.init( @@ -30,16 +31,34 @@ public class Session { owned: true) } - public static func createW3C(webDriver: any WebDriver, alwaysMatch: Capabilities, firstMatch: [Capabilities] = []) throws -> Session { + /// Initializer for W3C Protocol + private convenience init(webDriver: any WebDriver, alwaysMatch: Capabilities, firstMatch: [Capabilities]) throws { let response = try webDriver.send(Requests.Session_W3C( alwaysMatch: alwaysMatch, firstMatch: firstMatch)) - return Session( + self.init( webDriver: webDriver, existingId: response.value.sessionId, capabilities: response.value.capabilities, owned: true) } + public convenience init(webDriver: any WebDriver, capabilities: Capabilities) throws { + switch webDriver.wireProtocol { + case .legacySelenium: + try self.init(webDriver: webDriver, desiredCapabilities: capabilities, requiredCapabilities: capabilities) + case .w3c: + try self.init(webDriver: webDriver, alwaysMatch: capabilities, firstMatch: []) + } + } + + public static func createLegacy(webDriver: any WebDriver, desiredCapabilities: Capabilities, requiredCapabilities: Capabilities? = nil) throws -> Session { + try Session(webDriver: webDriver, desiredCapabilities: desiredCapabilities, requiredCapabilities: requiredCapabilities) + } + + public static func createW3C(webDriver: any WebDriver, alwaysMatch: Capabilities, firstMatch: [Capabilities] = []) throws -> Session { + try Session(webDriver: webDriver, alwaysMatch: alwaysMatch, firstMatch: firstMatch) + } + /// The amount of time the driver should implicitly wait when searching for elements. /// This functionality is either implemented by the driver, or emulated by swift-webdriver as a fallback. public var implicitWaitTimeout: TimeInterval { diff --git a/Sources/WebDriver/WebDriver.swift b/Sources/WebDriver/WebDriver.swift index c8e7417..3d5a506 100644 --- a/Sources/WebDriver/WebDriver.swift +++ b/Sources/WebDriver/WebDriver.swift @@ -13,10 +13,15 @@ public protocol WebDriver { extension WebDriver { /// status - returns WinAppDriver status - /// Returns: an instance of the Status type + /// Returns: an instance of the WebDriverStatus type public var status: WebDriverStatus { - get throws { try send(Requests.Status()) } + get throws { + switch wireProtocol { + case .legacySelenium: try send(Requests.Status_Legacy()) + case .w3c: try send(Requests.Status_W3C()).value + } + } } public func isInconclusiveInteraction(error: ErrorResponse.Status) -> Bool { false } -} \ No newline at end of file +} diff --git a/Tests/AppiumTests/AppiumTests.swift b/Tests/AppiumTests/AppiumTests.swift index f380303..db65386 100644 --- a/Tests/AppiumTests/AppiumTests.swift +++ b/Tests/AppiumTests/AppiumTests.swift @@ -23,8 +23,8 @@ final class AppiumTests: XCTestCase { capabilities.platformName = "windows" capabilities.appiumOptions = appiumOptions - let session = try Session.createW3C(webDriver: webDriver, alwaysMatch: capabilities) + let session = try Session(webDriver: webDriver, capabilities: capabilities) try session.sendKeys(.alt(.f4)) } #endif -} \ No newline at end of file +} diff --git a/Tests/UnitTests/APIToRequestMappingTests.swift b/Tests/UnitTests/APIToRequestMappingTests.swift index 256cddd..1b3d1de 100644 --- a/Tests/UnitTests/APIToRequestMappingTests.swift +++ b/Tests/UnitTests/APIToRequestMappingTests.swift @@ -13,7 +13,7 @@ class APIToRequestMappingTests: XCTestCase { capabilities.platformName = "myPlatform" return Requests.Session_Legacy.Response(sessionId: "mySession", value: capabilities) } - let session = try Session(webDriver: mockWebDriver, desiredCapabilities: Capabilities()) + let session = try Session(webDriver: mockWebDriver, capabilities: Capabilities()) XCTAssertEqual(session.id, "mySession") XCTAssertEqual(session.capabilities.platformName, "myPlatform") @@ -21,6 +21,28 @@ class APIToRequestMappingTests: XCTestCase { mockWebDriver.expect(path: "session/mySession", method: .delete) } + func testStatus_legacy() throws { + let mockWebDriver = MockWebDriver(wireProtocol: .legacySelenium) + mockWebDriver.expect(path: "status", method: .get, type: Requests.Status_Legacy.self) { + var status = WebDriverStatus() + status.ready = true + return status + } + + XCTAssertEqual(try mockWebDriver.status.ready, true) + } + + func testStatus_w3c() throws { + let mockWebDriver = MockWebDriver(wireProtocol: .w3c) + mockWebDriver.expect(path: "status", method: .get, type: Requests.Status_W3C.self) { + var status = WebDriverStatus() + status.ready = true + return Requests.Status_W3C.Response(status) + } + + XCTAssertEqual(try mockWebDriver.status.ready, true) + } + func testSessionTitle() throws { let mockWebDriver = MockWebDriver(wireProtocol: .legacySelenium) let session = Session(webDriver: mockWebDriver, existingId: "mySession") diff --git a/Tests/WinAppDriverTests/MSInfo32App.swift b/Tests/WinAppDriverTests/MSInfo32App.swift index c58b93a..86e5411 100644 --- a/Tests/WinAppDriverTests/MSInfo32App.swift +++ b/Tests/WinAppDriverTests/MSInfo32App.swift @@ -9,7 +9,7 @@ class MSInfo32App { init(winAppDriver: WinAppDriver) throws { let capabilities = WinAppDriver.Capabilities.startApp(name: "\(WindowsSystemPaths.system32)\\msinfo32.exe") - session = try Session(webDriver: winAppDriver, desiredCapabilities: capabilities, requiredCapabilities: capabilities) + session = try Session(webDriver: winAppDriver, capabilities: capabilities) session.implicitWaitTimeout = 1 } diff --git a/Tests/WinAppDriverTests/TimeoutTests.swift b/Tests/WinAppDriverTests/TimeoutTests.swift index 716cda5..f4f1bdf 100644 --- a/Tests/WinAppDriverTests/TimeoutTests.swift +++ b/Tests/WinAppDriverTests/TimeoutTests.swift @@ -24,7 +24,7 @@ class TimeoutTests: XCTestCase { // Use a simple app in which we can expect queries to execute quickly let capabilities = WinAppDriver.Capabilities.startApp( name: "\(WindowsSystemPaths.system32)\\winver.exe") - return try Session(webDriver: winAppDriver, desiredCapabilities: capabilities) + return try Session(webDriver: winAppDriver, capabilities: capabilities) } static func measureTime(_ callback: () throws -> Void) rethrows -> Double { From f6c1822c2d9384a486d4cc49e21043606f3bb831 Mon Sep 17 00:00:00 2001 From: Tristan Labelle Date: Tue, 29 Apr 2025 21:23:18 -0500 Subject: [PATCH 2/6] Missing returns --- Sources/WebDriver/WebDriver.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/WebDriver/WebDriver.swift b/Sources/WebDriver/WebDriver.swift index 3d5a506..ec7eac1 100644 --- a/Sources/WebDriver/WebDriver.swift +++ b/Sources/WebDriver/WebDriver.swift @@ -17,8 +17,8 @@ extension WebDriver { public var status: WebDriverStatus { get throws { switch wireProtocol { - case .legacySelenium: try send(Requests.Status_Legacy()) - case .w3c: try send(Requests.Status_W3C()).value + case .legacySelenium: return try send(Requests.Status_Legacy()) + case .w3c: return try send(Requests.Status_W3C()).value } } } From 32a4f13893738b80510c425b6ced07ff750f8c32 Mon Sep 17 00:00:00 2001 From: Tristan Labelle Date: Fri, 2 May 2025 08:09:48 -0500 Subject: [PATCH 3/6] Use LegacySelenium + W3C enum-namespaces. --- Sources/WebDriver/HTTPWebDriver.swift | 6 +- .../WebDriver/Requests+LegacySelenium.swift | 37 ++++++++++ Sources/WebDriver/Requests+W3C.swift | 41 +++++++++++ Sources/WebDriver/Requests.swift | 70 +------------------ Sources/WebDriver/Session.swift | 20 +++--- Sources/WebDriver/WebDriver.swift | 4 +- .../UnitTests/APIToRequestMappingTests.swift | 10 +-- 7 files changed, 101 insertions(+), 87 deletions(-) create mode 100644 Sources/WebDriver/Requests+LegacySelenium.swift create mode 100644 Sources/WebDriver/Requests+W3C.swift diff --git a/Sources/WebDriver/HTTPWebDriver.swift b/Sources/WebDriver/HTTPWebDriver.swift index 265992d..bd63282 100644 --- a/Sources/WebDriver/HTTPWebDriver.swift +++ b/Sources/WebDriver/HTTPWebDriver.swift @@ -25,7 +25,7 @@ public struct HTTPWebDriver: WebDriver { public static func detectProtocol(serverURL: URL) throws -> WireProtocol { // The status request is the same for the Selenium Legacy JSON protocol and W3C, // but the response format is different. - let urlRequest = try Self.buildURLRequest(serverURL: serverURL, Requests.Status_Legacy()) + let urlRequest = try Self.buildURLRequest(serverURL: serverURL, Requests.LegacySelenium.Status()) // Send the request and decode result or error let (status, responseData) = try urlRequest.send() @@ -33,9 +33,9 @@ public struct HTTPWebDriver: WebDriver { throw try JSONDecoder().decode(ErrorResponse.self, from: responseData) } - if let _ = try? JSONDecoder().decode(Requests.Status_Legacy.Response.self, from: responseData) { + if let _ = try? JSONDecoder().decode(Requests.LegacySelenium.Status.Response.self, from: responseData) { return .legacySelenium - } else if let _ = try? JSONDecoder().decode(Requests.Status_W3C.Response.self, from: responseData) { + } else if let _ = try? JSONDecoder().decode(Requests.LegacySelenium.Status.Response.self, from: responseData) { return .w3c } else { throw ProtocolDetectionError() diff --git a/Sources/WebDriver/Requests+LegacySelenium.swift b/Sources/WebDriver/Requests+LegacySelenium.swift new file mode 100644 index 0000000..d692405 --- /dev/null +++ b/Sources/WebDriver/Requests+LegacySelenium.swift @@ -0,0 +1,37 @@ +extension Requests { + /// Defines requests and response types specific to the legacy selenium json wire protocol. + public enum LegacySelenium { + // https://www.selenium.dev/documentation/legacy/json_wire_protocol/#session + public struct Session: Request { + public var desiredCapabilities: Caps + public var requiredCapabilities: Caps? + + public init(desiredCapabilities: Caps, requiredCapabilities: Caps? = nil) { + self.requiredCapabilities = requiredCapabilities + self.desiredCapabilities = desiredCapabilities + } + + public var pathComponents: [String] { ["session"] } + public var method: HTTPMethod { .post } + public var body: Body { .init(desiredCapabilities: desiredCapabilities, requiredCapabilities: requiredCapabilities) } + + public struct Body: Codable { + public var desiredCapabilities: Caps + public var requiredCapabilities: Caps? + } + + public struct Response: Codable { + public var sessionId: String + public var value: Caps + } + } + + // https://www.selenium.dev/documentation/legacy/json_wire_protocol/#status + public struct Status: Request { + public var pathComponents: [String] { ["status"] } + public var method: HTTPMethod { .get } + + public typealias Response = WebDriverStatus + } + } +} diff --git a/Sources/WebDriver/Requests+W3C.swift b/Sources/WebDriver/Requests+W3C.swift new file mode 100644 index 0000000..c83c077 --- /dev/null +++ b/Sources/WebDriver/Requests+W3C.swift @@ -0,0 +1,41 @@ +extension Requests { + /// Defines requests and response types specific to the W3C WebDriver protocol. + public enum W3C { + public struct Session: Request { + public var alwaysMatch: Caps + public var firstMatch: [Caps] + + public init(alwaysMatch: Caps, firstMatch: [Caps] = []) { + self.alwaysMatch = alwaysMatch + self.firstMatch = firstMatch + } + + public var pathComponents: [String] { ["session"] } + public var method: HTTPMethod { .post } + public var body: Body { .init(capabilities: .init(alwaysMatch: alwaysMatch, firstMatch: firstMatch)) } + + public struct Body: Codable { + public struct Capabilities: Codable { + public var alwaysMatch: Caps + public var firstMatch: [Caps]? + } + + public var capabilities: Capabilities + } + + public typealias Response = ResponseWithValue + + public struct ResponseValue: Codable { + public var sessionId: String + public var capabilities: Caps + } + } + + public struct Status: Request { + public var pathComponents: [String] { ["status"] } + public var method: HTTPMethod { .get } + + public typealias Response = ResponseWithValue + } + } +} diff --git a/Sources/WebDriver/Requests.swift b/Sources/WebDriver/Requests.swift index aab3295..6f83283 100644 --- a/Sources/WebDriver/Requests.swift +++ b/Sources/WebDriver/Requests.swift @@ -1,3 +1,4 @@ +/// Defines request and response types for the WebDriver protocol. public enum Requests { public struct ResponseWithValue: Codable where Value: Codable { public var value: Value @@ -160,60 +161,6 @@ public enum Requests { public typealias Response = ResponseWithValue } - public struct Session_Legacy: Request { - public var desiredCapabilities: Caps - public var requiredCapabilities: Caps? - - public init(desiredCapabilities: Caps, requiredCapabilities: Caps? = nil) { - self.requiredCapabilities = requiredCapabilities - self.desiredCapabilities = desiredCapabilities - } - - public var pathComponents: [String] { ["session"] } - public var method: HTTPMethod { .post } - public var body: Body { .init(desiredCapabilities: desiredCapabilities, requiredCapabilities: requiredCapabilities) } - - public struct Body: Codable { - public var desiredCapabilities: Caps - public var requiredCapabilities: Caps? - } - - public struct Response: Codable { - public var sessionId: String - public var value: Caps - } - } - - public struct Session_W3C: Request { - public var alwaysMatch: Caps - public var firstMatch: [Caps] - - public init(alwaysMatch: Caps, firstMatch: [Caps] = []) { - self.alwaysMatch = alwaysMatch - self.firstMatch = firstMatch - } - - public var pathComponents: [String] { ["session"] } - public var method: HTTPMethod { .post } - public var body: Body { .init(capabilities: .init(alwaysMatch: alwaysMatch, firstMatch: firstMatch)) } - - public struct Body: Codable { - public struct Capabilities: Codable { - public var alwaysMatch: Caps - public var firstMatch: [Caps]? - } - - public var capabilities: Capabilities - } - - public typealias Response = ResponseWithValue - - public struct ResponseValue: Codable { - public var sessionId: String - public var capabilities: Caps - } - } - // https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidelementactive public struct SessionActiveElement: Request { public var session: String @@ -662,21 +609,6 @@ public enum Requests { public typealias Response = ResponseWithValue } - // https://www.selenium.dev/documentation/legacy/json_wire_protocol/#status - public struct Status_Legacy: Request { - public var pathComponents: [String] { ["status"] } - public var method: HTTPMethod { .get } - - public typealias Response = WebDriverStatus - } - - public struct Status_W3C: Request { - public var pathComponents: [String] { ["status"] } - public var method: HTTPMethod { .get } - - public typealias Response = ResponseWithValue - } - // https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidorientation public enum SessionOrientation { public struct Post: Request { diff --git a/Sources/WebDriver/Session.swift b/Sources/WebDriver/Session.swift index 8bbc219..a8dee9f 100644 --- a/Sources/WebDriver/Session.swift +++ b/Sources/WebDriver/Session.swift @@ -21,8 +21,8 @@ public final class Session { } /// Initializer for Legacy Selenium JSON Protocol - private convenience init(webDriver: any WebDriver, desiredCapabilities: Capabilities, requiredCapabilities: Capabilities?) throws { - let response = try webDriver.send(Requests.Session_Legacy( + fileprivate convenience init(webDriver: any WebDriver, desiredCapabilities: Capabilities, requiredCapabilities: Capabilities?) throws { + let response = try webDriver.send(Requests.LegacySelenium.Session( desiredCapabilities: desiredCapabilities, requiredCapabilities: requiredCapabilities)) self.init( webDriver: webDriver, @@ -32,8 +32,8 @@ public final class Session { } /// Initializer for W3C Protocol - private convenience init(webDriver: any WebDriver, alwaysMatch: Capabilities, firstMatch: [Capabilities]) throws { - let response = try webDriver.send(Requests.Session_W3C( + fileprivate convenience init(webDriver: any WebDriver, alwaysMatch: Capabilities, firstMatch: [Capabilities]) throws { + let response = try webDriver.send(Requests.W3C.Session( alwaysMatch: alwaysMatch, firstMatch: firstMatch)) self.init( webDriver: webDriver, @@ -51,12 +51,16 @@ public final class Session { } } - public static func createLegacy(webDriver: any WebDriver, desiredCapabilities: Capabilities, requiredCapabilities: Capabilities? = nil) throws -> Session { - try Session(webDriver: webDriver, desiredCapabilities: desiredCapabilities, requiredCapabilities: requiredCapabilities) + public enum LegacySelenium { + public static func create(webDriver: any WebDriver, desiredCapabilities: Capabilities, requiredCapabilities: Capabilities? = nil) throws -> Session { + try Session(webDriver: webDriver, desiredCapabilities: desiredCapabilities, requiredCapabilities: requiredCapabilities) + } } - public static func createW3C(webDriver: any WebDriver, alwaysMatch: Capabilities, firstMatch: [Capabilities] = []) throws -> Session { - try Session(webDriver: webDriver, alwaysMatch: alwaysMatch, firstMatch: firstMatch) + public enum W3C { + public static func create(webDriver: any WebDriver, alwaysMatch: Capabilities, firstMatch: [Capabilities] = []) throws -> Session { + try Session(webDriver: webDriver, alwaysMatch: alwaysMatch, firstMatch: firstMatch) + } } /// The amount of time the driver should implicitly wait when searching for elements. diff --git a/Sources/WebDriver/WebDriver.swift b/Sources/WebDriver/WebDriver.swift index ec7eac1..d2e55af 100644 --- a/Sources/WebDriver/WebDriver.swift +++ b/Sources/WebDriver/WebDriver.swift @@ -17,8 +17,8 @@ extension WebDriver { public var status: WebDriverStatus { get throws { switch wireProtocol { - case .legacySelenium: return try send(Requests.Status_Legacy()) - case .w3c: return try send(Requests.Status_W3C()).value + case .legacySelenium: return try send(Requests.LegacySelenium.Status()) + case .w3c: return try send(Requests.W3C.Status()).value } } } diff --git a/Tests/UnitTests/APIToRequestMappingTests.swift b/Tests/UnitTests/APIToRequestMappingTests.swift index 1b3d1de..087a585 100644 --- a/Tests/UnitTests/APIToRequestMappingTests.swift +++ b/Tests/UnitTests/APIToRequestMappingTests.swift @@ -8,10 +8,10 @@ class APIToRequestMappingTests: XCTestCase { func testCreateSession() throws { let mockWebDriver = MockWebDriver(wireProtocol: .legacySelenium) - mockWebDriver.expect(path: "session", method: .post, type: Requests.Session_Legacy.self) { + mockWebDriver.expect(path: "session", method: .post, type: Requests.LegacySelenium.Session.self) { let capabilities = Capabilities() capabilities.platformName = "myPlatform" - return Requests.Session_Legacy.Response(sessionId: "mySession", value: capabilities) + return Requests.LegacySelenium.Session.Response(sessionId: "mySession", value: capabilities) } let session = try Session(webDriver: mockWebDriver, capabilities: Capabilities()) XCTAssertEqual(session.id, "mySession") @@ -23,7 +23,7 @@ class APIToRequestMappingTests: XCTestCase { func testStatus_legacy() throws { let mockWebDriver = MockWebDriver(wireProtocol: .legacySelenium) - mockWebDriver.expect(path: "status", method: .get, type: Requests.Status_Legacy.self) { + mockWebDriver.expect(path: "status", method: .get, type: Requests.LegacySelenium.Status.self) { var status = WebDriverStatus() status.ready = true return status @@ -34,10 +34,10 @@ class APIToRequestMappingTests: XCTestCase { func testStatus_w3c() throws { let mockWebDriver = MockWebDriver(wireProtocol: .w3c) - mockWebDriver.expect(path: "status", method: .get, type: Requests.Status_W3C.self) { + mockWebDriver.expect(path: "status", method: .get, type: Requests.W3C.Status.self) { var status = WebDriverStatus() status.ready = true - return Requests.Status_W3C.Response(status) + return Requests.W3C.Status.Response(status) } XCTAssertEqual(try mockWebDriver.status.ready, true) From 7931a0c60071d6f74e2f2071a8c5072e3c797708 Mon Sep 17 00:00:00 2001 From: Tristan Labelle Date: Fri, 2 May 2025 08:10:56 -0500 Subject: [PATCH 4/6] Update CMakeLists --- Sources/WebDriver/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Sources/WebDriver/CMakeLists.txt b/Sources/WebDriver/CMakeLists.txt index 32480d6..f829dd8 100644 --- a/Sources/WebDriver/CMakeLists.txt +++ b/Sources/WebDriver/CMakeLists.txt @@ -12,6 +12,8 @@ add_library(WebDriver Poll.swift Request.swift Requests.swift + Requests+LegacySelenium.swift + Requests+W3C.swift ScreenOrientation.swift Session.swift TimeoutType.swift From 1278b8db0f33219f965d4f459f016742affc6ac4 Mon Sep 17 00:00:00 2001 From: Tristan Labelle Date: Fri, 2 May 2025 13:16:59 -0400 Subject: [PATCH 5/6] Fix LegacySelenium that should be W3C --- Sources/WebDriver/HTTPWebDriver.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/WebDriver/HTTPWebDriver.swift b/Sources/WebDriver/HTTPWebDriver.swift index bd63282..55d2ea8 100644 --- a/Sources/WebDriver/HTTPWebDriver.swift +++ b/Sources/WebDriver/HTTPWebDriver.swift @@ -35,7 +35,7 @@ public struct HTTPWebDriver: WebDriver { if let _ = try? JSONDecoder().decode(Requests.LegacySelenium.Status.Response.self, from: responseData) { return .legacySelenium - } else if let _ = try? JSONDecoder().decode(Requests.LegacySelenium.Status.Response.self, from: responseData) { + } else if let _ = try? JSONDecoder().decode(Requests.W3C.Status.Response.self, from: responseData) { return .w3c } else { throw ProtocolDetectionError() From 036739b7649eb4106017842cd41310b313f0901e Mon Sep 17 00:00:00 2001 From: Tristan Labelle Date: Fri, 2 May 2025 13:18:23 -0400 Subject: [PATCH 6/6] legacy -> legacySelenium --- Tests/UnitTests/APIToRequestMappingTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/UnitTests/APIToRequestMappingTests.swift b/Tests/UnitTests/APIToRequestMappingTests.swift index 087a585..5dcf7d5 100644 --- a/Tests/UnitTests/APIToRequestMappingTests.swift +++ b/Tests/UnitTests/APIToRequestMappingTests.swift @@ -21,7 +21,7 @@ class APIToRequestMappingTests: XCTestCase { mockWebDriver.expect(path: "session/mySession", method: .delete) } - func testStatus_legacy() throws { + func testStatus_legacySelenium() throws { let mockWebDriver = MockWebDriver(wireProtocol: .legacySelenium) mockWebDriver.expect(path: "status", method: .get, type: Requests.LegacySelenium.Status.self) { var status = WebDriverStatus()