Skip to content

Commit

Permalink
Add initializers for attach vs launch, and cleanup test failure paths.
Browse files Browse the repository at this point in the history
  • Loading branch information
jeffdav committed Aug 4, 2023
1 parent 9809cee commit 6e31ba8
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 38 deletions.
4 changes: 4 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"lldb.library": "C:\\Program Files\\Swift\\Toolchains\\0.0.0+Asserts\\usr\\bin\\liblldb.dll",
"lldb.launch.expressions": "native"
}
92 changes: 61 additions & 31 deletions Sources/WinAppDriver.swift
Original file line number Diff line number Diff line change
@@ -1,47 +1,77 @@
import Foundation
import WinSDK

enum WinAppDriverError: Error {
public enum WinAppDriverError: Error {
// Exposes any underlying win32 errors that may surface as a result of process management.
case win32Error(lastError: Int)

// Attempting to attach to existing driver, but no existing WinAppDriver process was found.
case processNotFound

// Attempting to launch WinAppDriver, but it's already running.
case alreadyRunning
}

public class WinAppDriver: WebDriver {
static let ip = "127.0.0.1"
static let port = 4723
public static let defaultIp = "127.0.0.1"
public static let defaultPort = 4723

static let processsName = "WinAppDriver.exe"

private let httpWebDriver: HTTPWebDriver

let httpWebDriver: HTTPWebDriver
private let port: Int
private let ip: String

private var wadProcessInfo: PROCESS_INFORMATION?

public init(attachingTo ip: String, port: Int = WinAppDriver.defaultPort) throws {
self.ip = ip
self.port = port

// On local hosts, we can check if the process is running.
if ip == WinAppDriver.defaultIp {
guard isProcessRunning(withName: Self.processsName) else {
throw WinAppDriverError.processNotFound
}
}

httpWebDriver = HTTPWebDriver(endpoint: URL(string: "http://\(ip):\(port)")!)
}

public init() throws {
httpWebDriver = HTTPWebDriver(endpoint: URL(string: "http://\(Self.ip):\(Self.port)")!)

// Ensure WinAppDriver is running.
if !isProcessRunning(withName: "WinAppDriver.exe") {
let path = "\(ProcessInfo.processInfo.environment["ProgramFiles(x86)"]!)\\Windows Application Driver\\WinAppDriver.exe"
let commandLine = ["\"\(path)\"", Self.ip, String(Self.port)].joined(separator: " ")
try commandLine.withCString(encodedAs: UTF16.self) { commandLine throws in
var startupInfo = STARTUPINFOW()
startupInfo.cb = DWORD(MemoryLayout<STARTUPINFOW>.size)

var processInfo = PROCESS_INFORMATION()
guard CreateProcessW(
nil,
UnsafeMutablePointer<WCHAR>(mutating: commandLine),
nil,
nil,
false,
DWORD(CREATE_NEW_CONSOLE),
nil,
nil,
&startupInfo,
&processInfo
) else {
throw WinAppDriverError.win32Error(lastError: Int(GetLastError()))
}

wadProcessInfo = processInfo
ip = WinAppDriver.defaultIp
port = WinAppDriver.defaultPort

guard !isProcessRunning(withName: Self.processsName) else {
throw WinAppDriverError.alreadyRunning
}

httpWebDriver = HTTPWebDriver(endpoint: URL(string: "http://\(ip):\(port)")!)

let path = "\(ProcessInfo.processInfo.environment["ProgramFiles(x86)"]!)\\Windows Application Driver\\WinAppDriver.exe"
let commandLine = ["\"\(path)\"", ip, String(port)].joined(separator: " ")
try commandLine.withCString(encodedAs: UTF16.self) { commandLine throws in
var startupInfo = STARTUPINFOW()
startupInfo.cb = DWORD(MemoryLayout<STARTUPINFOW>.size)

var processInfo = PROCESS_INFORMATION()
guard CreateProcessW(
nil,
UnsafeMutablePointer<WCHAR>(mutating: commandLine),
nil,
nil,
false,
DWORD(CREATE_NEW_CONSOLE),
nil,
nil,
&startupInfo,
&processInfo
) else {
throw WinAppDriverError.win32Error(lastError: Int(GetLastError()))
}

wadProcessInfo = processInfo
}
}

Expand Down
15 changes: 14 additions & 1 deletion Tests/WebDriverTests/NotepadTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,22 @@ class Notepad {

class NotepadTests: XCTestCase {
static var winAppDriver: WinAppDriver!
static var setupError: WinAppDriverError?

override public class func setUp() {
XCTAssertNoThrow(winAppDriver = try WinAppDriver())
do {
winAppDriver = try WinAppDriver()
} catch let error as WinAppDriverError {
setupError = error
} catch {
assertionFailure("Unexpected error thrown.")
}
}

override public func setUpWithError() throws {
if let setupError = Self.setupError {
throw setupError
}
}

override public class func tearDown() {
Expand Down
23 changes: 18 additions & 5 deletions Tests/WebDriverTests/SessionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,28 @@ import XCTest

class SessionTests: XCTestCase {
static var session: Session!
static var setupError: Error?

override public class func setUp() {
guard let winAppDriver = try? WinAppDriver() else {
return XCTFail("Failed to start WinAppDriver")
do {
// We don't store webDriver as session maintains a reference.
let winAppDriver = try WinAppDriver()
let windowsDir = ProcessInfo.processInfo.environment["SystemRoot"]!
session = try winAppDriver.newSession(app: "\(windowsDir)\\System32\\msinfo32.exe")
} catch let error as WinAppDriverError {
setupError = error
} catch let error as WebDriverError {
setupError = error
} catch {
assertionFailure("Unexpected error thrown.")
}

// We don't store webDriver as session maintains a reference.
let windowsDir = ProcessInfo.processInfo.environment["SystemRoot"]!
XCTAssertNoThrow(session = try winAppDriver.newSession(app: "\(windowsDir)\\System32\\msinfo32.exe"))
}

override public func setUpWithError() throws {
if let setupError = Self.setupError {
throw setupError
}
}

override public class func tearDown() {
Expand Down
15 changes: 14 additions & 1 deletion Tests/WebDriverTests/StatusTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,22 @@ import XCTest

class StatusTest: XCTestCase {
static var winAppDriver: WinAppDriver!
static var setupError: WinAppDriverError?

override public class func setUp() {
XCTAssertNoThrow(winAppDriver = try WinAppDriver())
do {
winAppDriver = try WinAppDriver()
} catch let error as WinAppDriverError {
setupError = error
} catch {
assertionFailure("Unexpected error thrown.")
}
}

override public func setUpWithError() throws {
if let setupError = Self.setupError {
throw setupError
}
}

override public class func tearDown() {
Expand Down

0 comments on commit 6e31ba8

Please sign in to comment.