Skip to content

Commit b45eaa4

Browse files
authored
Merge branch 'main' into squid/window-handle
2 parents 5469663 + 0e62310 commit b45eaa4

File tree

9 files changed

+93
-19
lines changed

9 files changed

+93
-19
lines changed

Docs/SupportedAPIs.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,16 @@ Contributions to expand support to unimplemented functionality are always welcom
3737
| GET | `/session/:sessionId/element/:id/size` | Supported | `Element.size` |
3838
| GET | `/session/:sessionId/element/:id/text` | Supported | `Element.text` |
3939
| POST | `/session/:sessionId/element/:id/value` | Supported | `Element.sendKeys()`|
40+
| POST | `/session/:sessionId/execute` | Not Supported| `Session.execute()` |
41+
| POST | `/session/:sessionId/execute_async` | Not Supported| `Session.execute()` |
4042
| POST | `/session/:sessionId/forward` | Supported | `Session.forward()` |
4143
| POST | `/session/:sessionId/keys` | Supported | `Session.sendKeys()`|
4244
| GET | `/session/:sessionId/location` | Supported | Not implemented |
4345
| POST | `/session/:sessionId/moveto` | Supported | `Session.moveTo()` |
4446
| GET | `/session/:sessionId/orientation` | Supported | Not implemented |
4547
| POST | `/session/:sessionId/refresh` | Not supported| `Session.refresh()` |
4648
| GET | `/session/:sessionId/screenshot` | Supported | `Session.screenshot()`|
47-
| GET | `/session/:sessionId/source` | Supported | Not implemented |
49+
| GET | `/session/:sessionId/source` | Supported | `Session.source` |
4850
| POST | `/session/:sessionId/timeouts` | Supported | `Session.setTimeout()`|
4951
| GET | `/session/:sessionId/title` | Supported | `Session.title` |
5052
| POST | `/session/:sessionId/touch/click` | Supported | `Element.touchClick()`|

Package.swift

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,37 @@ import PackageDescription
55
let package = Package(
66
name: "swift-webdriver",
77
products: [
8-
.library(name: "WebDriver", targets: ["WebDriver", "WinAppDriver"]),
8+
.library(name: "WebDriver", targets: ["WebDriver"]),
99
],
1010
targets: [
1111
.target(
1212
name: "WebDriver",
1313
path: "Sources/WebDriver"),
14-
.target(
15-
name: "WinAppDriver",
16-
dependencies: ["WebDriver"],
17-
path: "Sources/WinAppDriver"),
1814
.target(
1915
name: "TestsCommon",
2016
path: "Tests/Common"),
21-
.testTarget(
22-
name: "WinAppDriverTests",
23-
dependencies: ["TestsCommon", "WebDriver", "WinAppDriver"],
24-
// Ignore "LNK4217: locally defined symbol imported" spew due to SPM library support limitations
25-
linkerSettings: [ .unsafeFlags(["-Xlinker", "-ignore:4217"]) ]),
2617
.testTarget(
2718
name: "UnitTests",
28-
dependencies: ["TestsCommon", "WebDriver", "WinAppDriver"],
19+
dependencies: ["TestsCommon", "WebDriver"],
2920
// Ignore "LNK4217: locally defined symbol imported" spew due to SPM library support limitations
30-
linkerSettings: [ .unsafeFlags(["-Xlinker", "-ignore:4217"]) ]),
21+
linkerSettings: [ .unsafeFlags(["-Xlinker", "-ignore:4217"], .when(platforms: [.windows])) ]),
3122
]
3223
)
24+
25+
#if os(Windows)
26+
package.products += [
27+
.library(name: "WinAppDriver", targets: ["WinAppDriver"])
28+
]
29+
package.targets += [
30+
.target(
31+
name: "WinAppDriver",
32+
dependencies: ["WebDriver"],
33+
path: "Sources/WinAppDriver"),
34+
.testTarget(
35+
name: "WinAppDriverTests",
36+
dependencies: ["TestsCommon", "WebDriver", "WinAppDriver"],
37+
// Ignore "LNK4217: locally defined symbol imported" spew due to SPM library support limitations
38+
linkerSettings: [ .unsafeFlags(["-Xlinker", "-ignore:4217"]) ]),
39+
]
40+
#endif
41+

Sources/WebDriver/HTTPWebDriver.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import Foundation
2+
#if canImport(FoundationNetworking)
23
import FoundationNetworking
4+
#endif
35

46
public struct HTTPWebDriver: WebDriver {
57
let rootURL: URL

Sources/WebDriver/Requests.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,23 @@ public enum Requests {
462462
}
463463
}
464464

465+
// https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidexecute
466+
// https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidexecute_async
467+
public struct SessionScript: Request {
468+
public var session: String
469+
public var script: String
470+
public var args: [String]
471+
public var async: Bool
472+
473+
public var pathComponents: [String] { ["session", session, async ? "execute_async" : "execute"] }
474+
public var method: HTTPMethod { .post }
475+
public var body: Body { .init(script: script, args: args) }
476+
public struct Body: Codable {
477+
public var script: String
478+
public var args: [String]
479+
}
480+
}
481+
465482
// https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidwindow
466483
public enum SessionWindow {
467484
public struct Post: Request {
@@ -524,6 +541,21 @@ public enum Requests {
524541
}
525542
}
526543

544+
// https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidsource
545+
public struct SessionSource: Request {
546+
public var session: String
547+
548+
public var pathComponents: [String] { ["session", session, "source"] }
549+
public var method: HTTPMethod {.get}
550+
551+
public typealias Response = ResponseWithValue<ResponseValue>
552+
553+
public struct ResponseValue: Codable {
554+
public var source: String
555+
}
556+
557+
}
558+
527559
// https://www.selenium.dev/documentation/legacy/json_wire_protocol/#status
528560
public struct Status: Request {
529561
public var pathComponents: [String] { ["status"] }

Sources/WebDriver/Session.swift

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ public class Session {
7373
Requests.SessionTimeouts(session: id, type: type, ms: duration * 1000))
7474
}
7575

76+
public func execute(script: String, args: [String] = [], async: Bool = false) throws {
77+
try webDriver.send(Requests.SessionScript(session: id, script: script, args: args, async: async))
78+
}
79+
7680
public func back() throws {
7781
try webDriver.send(Requests.SessionBack(session: id))
7882
}
@@ -317,12 +321,10 @@ public class Session {
317321
try webDriver.send(Requests.SessionWindowSize.Post(session: id, windowHandle: handle, width: width, height: height))
318322
}
319323

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

328330
/// Deletes the current session.

Sources/WebDriver/URLRequestExtensions.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import Foundation
2+
#if canImport(FoundationNetworking)
23
import FoundationNetworking
4+
#endif
35

46
extension URLSession {
57
func dataTask(

Sources/WinAppDriver/ErrorResponse+WinAppDriver.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import WebDriver
2+
13
extension ErrorResponse.Status {
24
// WinAppDriver returns when passing an incorrect window handle to attach to.
35
static let winAppDriver_invalidArgument = Self(rawValue: 100)

Tests/UnitTests/APIToRequestMappingTests.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,20 @@ class APIToRequestMappingTests: XCTestCase {
170170
XCTAssert(try element.enabled == true)
171171
}
172172

173+
func testSessionScript() throws {
174+
let mockWebDriver = MockWebDriver()
175+
let session = Session(webDriver: mockWebDriver, existingId: "mySession")
176+
mockWebDriver.expect(path: "session/mySession/execute", method: .post)
177+
XCTAssertNotNil(try session.execute(script: "return document.body", args: ["script"], async: false))
178+
}
179+
180+
func testSessionScriptAsync() throws {
181+
let mockWebDriver = MockWebDriver()
182+
let session = Session(webDriver: mockWebDriver, existingId: "mySession")
183+
mockWebDriver.expect(path: "session/mySession/execute_async", method: .post)
184+
XCTAssertNotNil(try session.execute(script: "return document.body", args: ["script"], async: true))
185+
}
186+
173187
func testSessionTouchScroll() throws {
174188
let mockWebDriver: MockWebDriver = MockWebDriver()
175189
let session = Session(webDriver: mockWebDriver, existingId: "mySession")
@@ -218,5 +232,14 @@ class APIToRequestMappingTests: XCTestCase {
218232
ResponseWithValue(.init(windowHandle: "", windowHandles: ["myWindow", "myWindow"]))
219233
}
220234
XCTAssert(try session.windowHandle(many: true) == (windowHandle: "", windowHandles: ["myWindow", "myWindow"]))
235+
236+
func testSessionSource() throws {
237+
let mockWebDriver: MockWebDriver = MockWebDriver()
238+
let session = Session(webDriver: mockWebDriver, existingId: "mySession")
239+
240+
mockWebDriver.expect(path: "session/mySession/source", method: .get, type: Requests.SessionSource.self) {
241+
ResponseWithValue(.init(source: "currentSource"))
242+
}
243+
XCTAssert(try session.source() == "currentSource")
221244
}
222245
}

0 commit comments

Comments
 (0)