From 5417268be5911fdae441e67368e1d6863aa1b8a7 Mon Sep 17 00:00:00 2001 From: Tristan Labelle Date: Mon, 28 Aug 2023 11:04:55 -0400 Subject: [PATCH] Cleanup WebDriverRequest struct (#68) --- Sources/Element+Request.swift | 6 ---- Sources/HTTPWebDriver.swift | 58 ++++++++++---------------------- Sources/Session+Requests.swift | 3 -- Sources/Session.swift | 1 - Sources/WebDriver+Requests.swift | 1 - Sources/WebDriverRequest.swift | 8 ++--- 6 files changed, 20 insertions(+), 57 deletions(-) diff --git a/Sources/Element+Request.swift b/Sources/Element+Request.swift index 056f4cc..176f735 100644 --- a/Sources/Element+Request.swift +++ b/Sources/Element+Request.swift @@ -26,7 +26,6 @@ extension Element { var pathComponents: [String] { ["session", element.session.id, "element", element.id, "click"] } var method: HTTPMethod { .post } - var body: Body { .init() } } /// text - the element text @@ -49,7 +48,6 @@ extension Element { var pathComponents: [String] { ["session", element.session.id, "element", element.id, "text"] } var method: HTTPMethod { .get } - var body: Body { .init() } } /// findElement(byName:) @@ -126,7 +124,6 @@ extension Element { var pathComponents: [String] { ["session", element.session.id, "element", element.id, "attribute", name] } var method: HTTPMethod { .get } - var body: Body = .init() } /// location - return x, y location of the element relative to the screen top left corner @@ -148,7 +145,6 @@ extension Element { var pathComponents: [String] { ["session", element.session.id, "element", element.id, "location"] } var method: HTTPMethod { .get } - var body: Body = .init() struct ResponseValue: Codable { let x: Int @@ -176,7 +172,6 @@ extension Element { var pathComponents: [String] { ["session", element.session.id, "element", element.id, "size"] } var method: HTTPMethod { .get } - var body: Body { .init() } struct ResponseValue: Codable { let width: Int @@ -202,7 +197,6 @@ extension Element { var pathComponents: [String] { ["session", element.session.id, "element", element.id, "displayed"] } var method: HTTPMethod { .get } - var body: Body = .init() // Override the whole Response struct instead of just ResponseValue // because the value property is a boolean instead of a struct diff --git a/Sources/HTTPWebDriver.swift b/Sources/HTTPWebDriver.swift index 9ccdae2..c9ca805 100644 --- a/Sources/HTTPWebDriver.swift +++ b/Sources/HTTPWebDriver.swift @@ -13,57 +13,35 @@ public struct HTTPWebDriver: WebDriver { // Send a WebDriverRequest to the web driver local service // TODO: consider making this function async/awaitable @discardableResult - public func send(_ request: Request) throws -> Request.Response where Request: WebDriverRequest { - // Create urlRequest with proper Url and method - let url = Self.buildURL(base: rootURL, pathComponents: request.pathComponents, query: request.query) - var urlRequest = URLRequest(url: url) - urlRequest.httpMethod = request.method.rawValue - // TODO: Setting timeoutInterval causes a crash when sending the request on the CI machines. - // https://linear.app/the-browser-company/issue/WIN-627/setting-timeoutinterval-on-urlrequest-makes-request-crash - // urlRequest.timeoutInterval = Self.defaultTimeout - - // Add the body if the WebDriverRequest type defines one - if Request.Body.self != CodableNone.self { - urlRequest.addValue("content-encoding", forHTTPHeaderField: "json") - urlRequest.addValue("application/json;charset=UTF-8", forHTTPHeaderField: "content-type") - urlRequest.httpBody = try JSONEncoder().encode(request.body) - } + public func send(_ request: Request) throws -> Request.Response { + let urlRequest = try buildURLRequest(request) // Send the request and decode result or error let (status, responseData) = try urlRequest.send() guard status == 200 else { - let error = try JSONDecoder().decode(WebDriverError.self, from: responseData) - throw error + throw try JSONDecoder().decode(WebDriverError.self, from: responseData) } - let res = try JSONDecoder().decode(Request.Response.self, from: responseData) - return res + return try JSONDecoder().decode(Request.Response.self, from: responseData) } - // Utility function to build a URL from its parts; inspired by GPT4. - private static func buildURL(base: URL, pathComponents: [String], query: [String: String] = [:]) -> URL { - var url = base - - // Append the path components - for pathComponent in pathComponents { - url.appendPathComponent(pathComponent) + private func buildURLRequest(_ request: Request) throws -> URLRequest { + var url = rootURL + for (index, pathComponent) in request.pathComponents.enumerated() { + let last = index == request.pathComponents.count - 1 + url.appendPathComponent(pathComponent, isDirectory: !last) } - if !query.isEmpty { - // Get the URL components - var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false)! - - // Convert dictionary to query items - let queryItems = query.map { key, value in - URLQueryItem(name: key, value: value) - } - - // Append query items to URL components - urlComponents.queryItems = queryItems + var urlRequest = URLRequest(url: url) + urlRequest.httpMethod = request.method.rawValue + // TODO(#40): Setting timeoutInterval causes a crash when sending the request on the CI machines. + // urlRequest.timeoutInterval = Self.defaultTimeout - // Get the final URL - url = urlComponents.url! + // Add the body if the WebDriverRequest type defines one + if Request.Body.self != CodableNone.self { + urlRequest.addValue("application/json;charset=UTF-8", forHTTPHeaderField: "content-type") + urlRequest.httpBody = try JSONEncoder().encode(request.body) } - return url + return urlRequest } } diff --git a/Sources/Session+Requests.swift b/Sources/Session+Requests.swift index e5ddb77..92c5ff3 100644 --- a/Sources/Session+Requests.swift +++ b/Sources/Session+Requests.swift @@ -21,7 +21,6 @@ extension Session { var pathComponents: [String] { ["session", session.id, "title"] } var method: HTTPMethod { .get } - var body: Body { .init() } } /// screenshot() @@ -50,7 +49,6 @@ extension Session { var pathComponents: [String] { ["session", session.id, "screenshot"] } var method: HTTPMethod { .get } - var body: Body { .init() } } /// findElement(byName:) @@ -173,7 +171,6 @@ extension Session { var pathComponents: [String] { ["session", session.id, "element", "active"] } var method: HTTPMethod { .post } - var body: Body = .init() struct ResponseValue: Codable { var element: String diff --git a/Sources/Session.swift b/Sources/Session.swift index ab1233e..90e4c7f 100644 --- a/Sources/Session.swift +++ b/Sources/Session.swift @@ -44,6 +44,5 @@ public class Session { let sessionId: String var pathComponents: [String] { ["session", sessionId] } var method: HTTPMethod { .delete } - var body: Body { .init() } } } diff --git a/Sources/WebDriver+Requests.swift b/Sources/WebDriver+Requests.swift index c0ebfd1..7474f6c 100644 --- a/Sources/WebDriver+Requests.swift +++ b/Sources/WebDriver+Requests.swift @@ -14,7 +14,6 @@ struct WebDriverStatusRequest: WebDriverRequest { var pathComponents: [String] { ["status"] } var method: HTTPMethod { .get } - var body: Body { .init() } } public struct WebDriverStatus: Codable { diff --git a/Sources/WebDriverRequest.swift b/Sources/WebDriverRequest.swift index b8ecaac..ca051b6 100644 --- a/Sources/WebDriverRequest.swift +++ b/Sources/WebDriverRequest.swift @@ -9,16 +9,12 @@ public protocol WebDriverRequest { associatedtype Response: Codable = WebDriverResponse var pathComponents: [String] { get } - var query: [String: String] { get } var method: HTTPMethod { get } var body: Body { get } } -// Provide a default for the query part of the request URL -// Saves protocol implementers from having to define if they do not use -// TODO: is there a way to provide a default for body? -extension WebDriverRequest { - public var query: [String: String] { [:] } +extension WebDriverRequest where Body == CodableNone { + var body: Body { .init() } } public enum HTTPMethod: String {