Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .dotfiles
Submodule .dotfiles updated 1 files
+1 −0 .swiftformat-base
52 changes: 52 additions & 0 deletions Sources/SwiftWebDriver/API/Request/ActionsPayload.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// ActionsPayload.swift
// Copyright (c) 2025 GetAutomaApp
// All source code and related assets are the property of GetAutomaApp.
// All rights reserved.

struct WebDriverElementOrigin: Encodable {
let element: String

enum CodingKeys: String, CodingKey {
case element = "element-6066-11e4-a52e-4f735466cecf"
}
}

struct PointerAction: Encodable {
let type: String
let origin: WebDriverElementOrigin?
let x: Int?

Check failure on line 17 in Sources/SwiftWebDriver/API/Request/ActionsPayload.swift

View workflow job for this annotation

GitHub Actions / swiftlint

Variable name 'x' should be between 3 and 40 characters long (identifier_name)
let y: Int?

Check failure on line 18 in Sources/SwiftWebDriver/API/Request/ActionsPayload.swift

View workflow job for this annotation

GitHub Actions / swiftlint

Variable name 'y' should be between 3 and 40 characters long (identifier_name)
let button: Int?
let duration: Int?

init(
type: String,
origin: WebDriverElementOrigin? = nil,
x: Int? = nil,

Check failure on line 25 in Sources/SwiftWebDriver/API/Request/ActionsPayload.swift

View workflow job for this annotation

GitHub Actions / swiftlint

Variable name 'x' should be between 3 and 40 characters long (identifier_name)
y: Int? = nil,

Check failure on line 26 in Sources/SwiftWebDriver/API/Request/ActionsPayload.swift

View workflow job for this annotation

GitHub Actions / swiftlint

Variable name 'y' should be between 3 and 40 characters long (identifier_name)
button: Int? = nil,
duration: Int? = nil
) {
self.type = type
self.origin = origin
self.x = x
self.y = y
self.button = button
self.duration = duration
}
}

struct PointerSource: Encodable {
let type: String
let id: String
let parameters: Parameters
let actions: [PointerAction]

struct Parameters: Encodable {
let pointerType: String
}
}

struct ActionsPayload: Encodable {
let actions: [PointerSource]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// GetElementRectRequest.swift
// Copyright (c) 2025 GetAutomaApp
// All source code and related assets are the property of GetAutomaApp.
// All rights reserved.

import AsyncHTTPClient
import Foundation
import NIO
import NIOHTTP1

internal struct GetElementRectRequest: RequestType {
typealias Response = GetElementRectResponse

var baseURL: URL
var sessionId: String
var elementId: String

var path: String { "session/\(sessionId)/element/\(elementId)/rect" }
var method: HTTPMethod = .GET
var headers: HTTPHeaders = [:]
var body: HTTPClient.Body? { nil }
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,51 +58,3 @@ internal struct PostElementDoubleClickRequest: RequestType {
return .data(data)
}
}

struct WebDriverElementOrigin: Encodable {
let element: String

enum CodingKeys: String, CodingKey {
case element = "element-6066-11e4-a52e-4f735466cecf"
}
}

struct PointerAction: Encodable {
let type: String
let origin: WebDriverElementOrigin?
let x: Int?
let y: Int?
let button: Int?
let duration: Int?

init(
type: String,
origin: WebDriverElementOrigin? = nil,
x: Int? = nil,
y: Int? = nil,
button: Int? = nil,
duration: Int? = nil
) {
self.type = type
self.origin = origin
self.x = x
self.y = y
self.button = button
self.duration = duration
}
}

struct PointerSource: Encodable {
let type: String
let id: String
let parameters: Parameters
let actions: [PointerAction]

struct Parameters: Encodable {
let pointerType: String
}
}

struct ActionsPayload: Encodable {
let actions: [PointerSource]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// PostElementDragAndDropRequest.swift
// Copyright (c) 2025 GetAutomaApp
// All source code and related assets are the property of GetAutomaApp.
// All rights reserved.

import AnyCodable
import AsyncHTTPClient
import Foundation
import NIO
import NIOHTTP1

internal struct PostElementDragAndDropRequest: RequestType {
typealias Response = PostElementClickResponse

var baseURL: URL

var sessionId: String

var elementId: String

var toElementId: String

var elementRect: ElementRect

var targetElementRect: ElementRect

var path: String {
"session/\(sessionId)/actions"
}

var method: HTTPMethod = .POST

var headers: HTTPHeaders = [:]

var body: HTTPClient.Body? {
let origin = WebDriverElementOrigin(element: elementId)
let dragToOrigin = WebDriverElementOrigin(element: toElementId)

// let sourceCenterX = Int(elementRect.width / 2)
// let sourceCenterY = Int(elementRect.height / 2)
//
let targetCenterX = Int(targetElementRect.width / 2)
let targetCenterY = Int(targetElementRect.height / 2)

let pointerActions = [
// PointerAction(type: "pointerMove", origin: origin, x: sourceCenterX, y: sourceCenterY),
PointerAction(type: "pointerMove", origin: origin, x: 0, y: 0),
PointerAction(type: "pointerDown", button: 0),
PointerAction(type: "pause", duration: 100),
PointerAction(type: "pointerMove", origin: dragToOrigin, x: targetCenterX, y: targetCenterY),
PointerAction(type: "pointerUp", button: 0)
]

let pointerSource = PointerSource(
type: "pointer",
id: "mouse",
parameters: .init(pointerType: "mouse"),
actions: pointerActions
)

let payload = ActionsPayload(actions: [pointerSource])

let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let data = try? encoder.encode(payload)

guard let data else {
return nil
}

return .data(data)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// GetElementRectResponse.swift
// Copyright (c) 2025 GetAutomaApp
// All source code and related assets are the property of GetAutomaApp.
// All rights reserved.

import Foundation

public struct GetElementRectResponse: ResponseType {
public let value: ElementRect
}
28 changes: 28 additions & 0 deletions Sources/SwiftWebDriver/Element/Element.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@
func name() async throws -> String
func click() async throws -> String?
func doubleClick() async throws -> String?
func dragAndDrop(to: Element) async throws -> String?

Check failure on line 20 in Sources/SwiftWebDriver/Element/Element.swift

View workflow job for this annotation

GitHub Actions / swiftlint

Variable name 'to' should be between 3 and 40 characters long (identifier_name)
func clear() async throws -> String?
func attribute(name: String) async throws -> String
func send(value: String) async throws -> String?
func screenshot() async throws -> String
func rect() async throws -> ElementRect
}

public struct Element: ElementCommandProtocol, Sendable {
Expand Down Expand Up @@ -85,6 +87,32 @@
return response.value
}

@discardableResult
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
public func dragAndDrop(to: Element) async throws -> String? {

Check failure on line 92 in Sources/SwiftWebDriver/Element/Element.swift

View workflow job for this annotation

GitHub Actions / swiftlint

Variable name 'to' should be between 3 and 40 characters long (identifier_name)
let request = try await PostElementDragAndDropRequest(
baseURL: baseURL,
sessionId: sessionId,
elementId: elementId,
toElementId: to.elementId,
elementRect: rect(),
targetElementRect: to.rect()
)
let response = try await APIClient.shared.request(request)
return response.value
}

@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
public func rect() async throws -> ElementRect {
let request = GetElementRectRequest(
baseURL: baseURL,
sessionId: sessionId,
elementId: elementId
)
let response = try await APIClient.shared.request(request)
return response.value
}

@discardableResult
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
public func clear() async throws -> String? {
Expand Down
11 changes: 11 additions & 0 deletions Sources/SwiftWebDriver/Element/ElementRect.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// ElementRect.swift
// Copyright (c) 2025 GetAutomaApp
// All source code and related assets are the property of GetAutomaApp.
// All rights reserved.

public struct ElementRect: Codable, Sendable {
public let x: Double

Check failure on line 7 in Sources/SwiftWebDriver/Element/ElementRect.swift

View workflow job for this annotation

GitHub Actions / swiftlint

Variable name 'x' should be between 3 and 40 characters long (identifier_name)
public let y: Double

Check failure on line 8 in Sources/SwiftWebDriver/Element/ElementRect.swift

View workflow job for this annotation

GitHub Actions / swiftlint

Variable name 'y' should be between 3 and 40 characters long (identifier_name)
public let width: Double
public let height: Double
}
5 changes: 5 additions & 0 deletions Sources/SwiftWebDriver/WebDriver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import Foundation
import NIOCore

public class WebDriver<T: Driver> {

Check warning on line 9 in Sources/SwiftWebDriver/WebDriver.swift

View workflow job for this annotation

GitHub Actions / swiftlint

public declarations should be documented (missing_docs)
private let driver: T

/// init webDriver
Expand Down Expand Up @@ -43,7 +43,7 @@
}

@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
public func getNavigation() async throws -> GetNavigationResponse {

Check warning on line 46 in Sources/SwiftWebDriver/WebDriver.swift

View workflow job for this annotation

GitHub Actions / swiftlint

public declarations should be documented (missing_docs)
try await driver.getNavigation()
}

Expand All @@ -57,7 +57,7 @@
}

@discardableResult
public func navigateTo(url: URL) async throws -> PostNavigationResponse {

Check warning on line 60 in Sources/SwiftWebDriver/WebDriver.swift

View workflow job for this annotation

GitHub Actions / swiftlint

public declarations should be documented (missing_docs)
try await navigateTo(urlString: url.absoluteString)
}

Expand All @@ -79,17 +79,17 @@

@discardableResult
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
public func navigationRefresh() async throws -> PostNavigationRefreshResponse {

Check warning on line 82 in Sources/SwiftWebDriver/WebDriver.swift

View workflow job for this annotation

GitHub Actions / swiftlint

public declarations should be documented (missing_docs)
try await driver.postNavigationRefresh()
}

@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
public func navigationTitle() async throws -> GetNavigationTitleResponse {

Check warning on line 87 in Sources/SwiftWebDriver/WebDriver.swift

View workflow job for this annotation

GitHub Actions / swiftlint

public declarations should be documented (missing_docs)
try await driver.getNavigationTitle()
}

@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
public func findElement(_ locatorType: LocatorType) async throws -> Element {

Check warning on line 92 in Sources/SwiftWebDriver/WebDriver.swift

View workflow job for this annotation

GitHub Actions / swiftlint

public declarations should be documented (missing_docs)
try await driver.findElement(locatorType)
}

Expand Down Expand Up @@ -143,4 +143,9 @@
public func setProperty(element: Element, propertyName: String, newValue: String) async throws {
try await driver.setProperty(element: element, propertyName: propertyName, newValue: newValue)
}

@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
public func dragAndDrop(from source: Element, to target: Element) async throws {
try await driver.dragAndDrop(from: source, to: target)
}
}
4 changes: 4 additions & 0 deletions Sources/SwiftWebDriver/WebDrivers/Chrome/ChromeDriver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,10 @@ public class ChromeDriver: Driver {
try await execute(script, args: args, type: .sync)
}

public func dragAndDrop(from source: Element, to target: Element) async throws {
try await ChromeDriverElementDragAndDropper(driver: self, from: source, to: target).dragAndDrop()
}

deinit {
let url = url
let sessionId = sessionId
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// ChromeDriverElementDragAndDropper.swift
// Copyright (c) 2025 GetAutomaApp
// All source code and related assets are the property of GetAutomaApp.
// All rights reserved.

internal struct ChromeDriverElementDragAndDropper {
let source: Element
let target: Element
let driver: ChromeDriver

public init(driver: ChromeDriver, from source: Element, to target: Element) {
self.driver = driver
self.source = source
self.target = target
}

public func dragAndDrop() async throws {
if try await isHTML5Draggable() {
try await simulateHTML5DragAndDrop()
} else {
try await source.dragAndDrop(to: target)
}
}

private func simulateHTML5DragAndDrop() async throws {
let script = """
function simulateHTML5DragAndDrop(source, target) {
const dataTransfer = new DataTransfer();

const dragStartEvent = new DragEvent('dragstart', {
bubbles: true,
cancelable: true,
dataTransfer: dataTransfer
});
source.dispatchEvent(dragStartEvent);

const dragOverEvent = new DragEvent('dragover', {
bubbles: true,
cancelable: true,
dataTransfer: dataTransfer
});
target.dispatchEvent(dragOverEvent);

const dropEvent = new DragEvent('drop', {
bubbles: true,
cancelable: true,
dataTransfer: dataTransfer
});
target.dispatchEvent(dropEvent);
}
simulateHTML5DragAndDrop(arguments[0], arguments[1]);
"""
let arguments: [AnyEncodable] = [
AnyEncodable(["element-6066-11e4-a52e-4f735466cecf": source.elementId]),
AnyEncodable(["element-6066-11e4-a52e-4f735466cecf": target.elementId])
]
try await driver.execute(script, args: arguments, type: .sync)
}

private func isHTML5Draggable() async throws -> Bool {
let draggableValue = try await source.attribute(name: "draggable")
return draggableValue.lowercased() == "true"
}
}
2 changes: 2 additions & 0 deletions Sources/SwiftWebDriver/WebDrivers/Driver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,6 @@ public protocol Driver: FindElementProtocol {
func getProperty(element: Element, propertyName: String) async throws -> PostExecuteResponse

func setProperty(element: Element, propertyName: String, newValue: String) async throws

func dragAndDrop(from source: Element, to target: Element) async throws
}
Loading
Loading