Skip to content

Commit

Permalink
Merge branch 'main' into squid/window-handle
Browse files Browse the repository at this point in the history
  • Loading branch information
Squidonomics authored Feb 23, 2024
2 parents 5469663 + 0e62310 commit b45eaa4
Show file tree
Hide file tree
Showing 9 changed files with 93 additions and 19 deletions.
4 changes: 3 additions & 1 deletion Docs/SupportedAPIs.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,16 @@ Contributions to expand support to unimplemented functionality are always welcom
| GET | `/session/:sessionId/element/:id/size` | Supported | `Element.size` |
| GET | `/session/:sessionId/element/:id/text` | Supported | `Element.text` |
| POST | `/session/:sessionId/element/:id/value` | Supported | `Element.sendKeys()`|
| POST | `/session/:sessionId/execute` | Not Supported| `Session.execute()` |
| POST | `/session/:sessionId/execute_async` | Not Supported| `Session.execute()` |
| POST | `/session/:sessionId/forward` | Supported | `Session.forward()` |
| POST | `/session/:sessionId/keys` | Supported | `Session.sendKeys()`|
| GET | `/session/:sessionId/location` | Supported | Not implemented |
| POST | `/session/:sessionId/moveto` | Supported | `Session.moveTo()` |
| GET | `/session/:sessionId/orientation` | Supported | Not implemented |
| POST | `/session/:sessionId/refresh` | Not supported| `Session.refresh()` |
| GET | `/session/:sessionId/screenshot` | Supported | `Session.screenshot()`|
| GET | `/session/:sessionId/source` | Supported | Not implemented |
| GET | `/session/:sessionId/source` | Supported | `Session.source` |
| POST | `/session/:sessionId/timeouts` | Supported | `Session.setTimeout()`|
| GET | `/session/:sessionId/title` | Supported | `Session.title` |
| POST | `/session/:sessionId/touch/click` | Supported | `Element.touchClick()`|
Expand Down
33 changes: 21 additions & 12 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,37 @@ import PackageDescription
let package = Package(
name: "swift-webdriver",
products: [
.library(name: "WebDriver", targets: ["WebDriver", "WinAppDriver"]),
.library(name: "WebDriver", targets: ["WebDriver"]),
],
targets: [
.target(
name: "WebDriver",
path: "Sources/WebDriver"),
.target(
name: "WinAppDriver",
dependencies: ["WebDriver"],
path: "Sources/WinAppDriver"),
.target(
name: "TestsCommon",
path: "Tests/Common"),
.testTarget(
name: "WinAppDriverTests",
dependencies: ["TestsCommon", "WebDriver", "WinAppDriver"],
// Ignore "LNK4217: locally defined symbol imported" spew due to SPM library support limitations
linkerSettings: [ .unsafeFlags(["-Xlinker", "-ignore:4217"]) ]),
.testTarget(
name: "UnitTests",
dependencies: ["TestsCommon", "WebDriver", "WinAppDriver"],
dependencies: ["TestsCommon", "WebDriver"],
// Ignore "LNK4217: locally defined symbol imported" spew due to SPM library support limitations
linkerSettings: [ .unsafeFlags(["-Xlinker", "-ignore:4217"]) ]),
linkerSettings: [ .unsafeFlags(["-Xlinker", "-ignore:4217"], .when(platforms: [.windows])) ]),
]
)

#if os(Windows)
package.products += [
.library(name: "WinAppDriver", targets: ["WinAppDriver"])
]
package.targets += [
.target(
name: "WinAppDriver",
dependencies: ["WebDriver"],
path: "Sources/WinAppDriver"),
.testTarget(
name: "WinAppDriverTests",
dependencies: ["TestsCommon", "WebDriver", "WinAppDriver"],
// Ignore "LNK4217: locally defined symbol imported" spew due to SPM library support limitations
linkerSettings: [ .unsafeFlags(["-Xlinker", "-ignore:4217"]) ]),
]
#endif

2 changes: 2 additions & 0 deletions Sources/WebDriver/HTTPWebDriver.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif

public struct HTTPWebDriver: WebDriver {
let rootURL: URL
Expand Down
32 changes: 32 additions & 0 deletions Sources/WebDriver/Requests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,23 @@ public enum Requests {
}
}

// https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidexecute
// https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidexecute_async
public struct SessionScript: Request {
public var session: String
public var script: String
public var args: [String]
public var async: Bool

public var pathComponents: [String] { ["session", session, async ? "execute_async" : "execute"] }
public var method: HTTPMethod { .post }
public var body: Body { .init(script: script, args: args) }
public struct Body: Codable {
public var script: String
public var args: [String]
}
}

// https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidwindow
public enum SessionWindow {
public struct Post: Request {
Expand Down Expand Up @@ -524,6 +541,21 @@ public enum Requests {
}
}

// https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidsource
public struct SessionSource: Request {
public var session: String

public var pathComponents: [String] { ["session", session, "source"] }
public var method: HTTPMethod {.get}

public typealias Response = ResponseWithValue<ResponseValue>

public struct ResponseValue: Codable {
public var source: String
}

}

// https://www.selenium.dev/documentation/legacy/json_wire_protocol/#status
public struct Status: Request {
public var pathComponents: [String] { ["status"] }
Expand Down
14 changes: 8 additions & 6 deletions Sources/WebDriver/Session.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ public class Session {
Requests.SessionTimeouts(session: id, type: type, ms: duration * 1000))
}

public func execute(script: String, args: [String] = [], async: Bool = false) throws {
try webDriver.send(Requests.SessionScript(session: id, script: script, args: args, async: async))
}

public func back() throws {
try webDriver.send(Requests.SessionBack(session: id))
}
Expand Down Expand Up @@ -317,12 +321,10 @@ public class Session {
try webDriver.send(Requests.SessionWindowSize.Post(session: id, windowHandle: handle, width: width, height: height))
}

///
/// - Parameter many: Bool value that will return multiple window handles
/// - Returns: either current window handle or many based on bool flag
public func windowHandle(many: Bool) throws -> (windowHandle: String, windowHandles: [String]) {
let response = try webDriver.send(Requests.SessionWindowHandle(session: id, many: many))
return (windowHandle: response.value.windowHandle, windowHandles: response.value.windowHandles)
/// - Returns: The current page source.
public func source() throws -> String {
let response = try webDriver.send(Requests.SessionSource(session: id))
return response.value.source
}

/// Deletes the current session.
Expand Down
2 changes: 2 additions & 0 deletions Sources/WebDriver/URLRequestExtensions.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif

extension URLSession {
func dataTask(
Expand Down
2 changes: 2 additions & 0 deletions Sources/WinAppDriver/ErrorResponse+WinAppDriver.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import WebDriver

extension ErrorResponse.Status {
// WinAppDriver returns when passing an incorrect window handle to attach to.
static let winAppDriver_invalidArgument = Self(rawValue: 100)
Expand Down
23 changes: 23 additions & 0 deletions Tests/UnitTests/APIToRequestMappingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,20 @@ class APIToRequestMappingTests: XCTestCase {
XCTAssert(try element.enabled == true)
}

func testSessionScript() throws {
let mockWebDriver = MockWebDriver()
let session = Session(webDriver: mockWebDriver, existingId: "mySession")
mockWebDriver.expect(path: "session/mySession/execute", method: .post)
XCTAssertNotNil(try session.execute(script: "return document.body", args: ["script"], async: false))
}

func testSessionScriptAsync() throws {
let mockWebDriver = MockWebDriver()
let session = Session(webDriver: mockWebDriver, existingId: "mySession")
mockWebDriver.expect(path: "session/mySession/execute_async", method: .post)
XCTAssertNotNil(try session.execute(script: "return document.body", args: ["script"], async: true))
}

func testSessionTouchScroll() throws {
let mockWebDriver: MockWebDriver = MockWebDriver()
let session = Session(webDriver: mockWebDriver, existingId: "mySession")
Expand Down Expand Up @@ -218,5 +232,14 @@ class APIToRequestMappingTests: XCTestCase {
ResponseWithValue(.init(windowHandle: "", windowHandles: ["myWindow", "myWindow"]))
}
XCTAssert(try session.windowHandle(many: true) == (windowHandle: "", windowHandles: ["myWindow", "myWindow"]))

func testSessionSource() throws {
let mockWebDriver: MockWebDriver = MockWebDriver()
let session = Session(webDriver: mockWebDriver, existingId: "mySession")

mockWebDriver.expect(path: "session/mySession/source", method: .get, type: Requests.SessionSource.self) {
ResponseWithValue(.init(source: "currentSource"))
}
XCTAssert(try session.source() == "currentSource")
}
}
File renamed without changes.

0 comments on commit b45eaa4

Please sign in to comment.