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
16 changes: 16 additions & 0 deletions Sources/SwiftWebDriver/API/Request/DevTools/AnyEncodable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// AnyEncodable.swift
// Copyright (c) 2025 GetAutomaApp
// All source code and related assets are the property of GetAutomaApp.
// All rights reserved.

public struct AnyEncodable: Encodable {
private let encodeFunc: (Encoder) throws -> Void

init(_ value: some Encodable) {
encodeFunc = value.encode
}

public func encode(to encoder: Encoder) throws {
try encodeFunc(encoder)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,9 @@ internal struct PostExecuteAsyncRequest: RequestType {

return .data(data)
}
}

internal extension PostExecuteAsyncRequest {
struct RequestBody: Codable {
public let script: String
public let args: [String]
struct RequestBody: Encodable {
let script: String
let args: [AnyEncodable]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ internal struct PostExecuteSyncRequest: RequestType {
}

internal extension PostExecuteSyncRequest {
struct RequestBody: Codable {
public let script: String
public let args: [String]
struct RequestBody: Encodable {
let script: String
let args: [AnyEncodable]
}
}
7 changes: 6 additions & 1 deletion Sources/SwiftWebDriver/WebDriver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import Foundation
import NIOCore

public class WebDriver<T: Driver> {

Check warning on line 12 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 @@ -46,7 +46,7 @@
}

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

Check warning on line 49 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 @@ -60,7 +60,7 @@
}

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

Check warning on line 63 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 @@ -82,12 +82,12 @@

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

Check warning on line 85 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 90 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()
}

Expand Down Expand Up @@ -120,7 +120,7 @@
@discardableResult
public func execute(
_ script: String,
args: [String] = [],
args: [AnyEncodable] = [],
type: DevToolTypes.JavascriptExecutionTypes = .sync
) async throws -> PostExecuteResponse {
try await driver.execute(script, args: args, type: type)
Expand All @@ -131,4 +131,9 @@
public func getActiveElement() async throws -> Element {
try await driver.getActiveElement()
}

@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
func setAttribute(element: Element, attributeName: String, newValue: String) async throws {

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

View workflow job for this annotation

GitHub Actions / swiftlint

All declarations should specify Access Control Level keywords explicitly (explicit_acl)
try await driver.setAttribute(element: element, attributeName: attributeName, newValue: newValue)
}
}
17 changes: 14 additions & 3 deletions Sources/SwiftWebDriver/WebDrivers/Chrome/ChromeDriver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ public class ChromeDriver: Driver {
}
}

private func executeJavascriptSync(_ script: String, args: [String]) async throws -> PostExecuteResponse {
private func executeJavascriptSync(_ script: String, args: [AnyEncodable]) async throws -> PostExecuteResponse {
guard let sessionId else {
throw WebDriverError.sessionIdIsNil
}
Expand All @@ -261,7 +261,7 @@ public class ChromeDriver: Driver {
return try await client.request(request)
}

private func executeJavascriptAsync(_ script: String, args: [String]) async throws -> PostExecuteResponse {
private func executeJavascriptAsync(_ script: String, args: [AnyEncodable]) async throws -> PostExecuteResponse {
guard let sessionId else {
throw WebDriverError.sessionIdIsNil
}
Expand All @@ -279,7 +279,7 @@ public class ChromeDriver: Driver {
@discardableResult
public func execute(
_ script: String,
args: [String],
args: [AnyEncodable],
type: DevToolTypes.JavascriptExecutionTypes
) async throws -> PostExecuteResponse {
try await type == .sync ?
Expand All @@ -301,6 +301,17 @@ public class ChromeDriver: Driver {
return Element(baseURL: url, sessionId: sessionId, elementId: response.elementId)
}

public func setAttribute(element: Element, attributeName: String, newValue: String) async throws {
let script = "arguments[0].setAttribute(arguments[1], arguments[2]);"

let args: [AnyEncodable] = [
AnyEncodable(["element-6066-11e4-a52e-4f735466cecf": element.elementId]),
AnyEncodable(attributeName),
AnyEncodable(newValue)
]
try await execute(script, args: args, type: .sync)
}

deinit {
let url = url
let sessionId = sessionId
Expand Down
4 changes: 3 additions & 1 deletion Sources/SwiftWebDriver/WebDrivers/Driver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,11 @@ public protocol Driver: FindElementProtocol {

func execute(
_ script: String,
args: [String],
args: [AnyEncodable],
type: DevToolTypes.JavascriptExecutionTypes
) async throws -> PostExecuteResponse

func getActiveElement() async throws -> Element

func setAttribute(element: Element, attributeName: String, newValue: String) async throws
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// ChromeDriverSetAttributeIntegrationTests.swift
// Copyright (c) 2025 GetAutomaApp
// All source code and related assets are the property of GetAutomaApp.
// All rights reserved.

@testable import SwiftWebDriver
import Testing

@Suite("Chrome Driver Set Attribute", .serialized)
internal class ChromeDriverSetAttributeIntegrationTests: ChromeDriverTest {
@Test("Set Attribute")
public func setAttribute() async throws {
page = "elementHandleTestPage.html"
try await driver.navigateTo(urlString: testPageURL.absoluteString)

let element = try await driver.findElement(.css(.id("attribute")))
let newIdentifier = "newidentifier"
try await driver.setAttribute(element: element, attributeName: "id", newValue: newIdentifier)

let elementId = try await element.attribute(name: "id")
#expect(elementId == newIdentifier)
}

deinit {
// Add deinit logic here
}
}
8 changes: 8 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@
"install:all": "npx npm-run-all install:swiftformat install:swiftlint config",
"install:swiftformat": "brew install swiftformat",
"install:swiftlint": "brew install swiftlint",
"compose:up": "npm run compose -- up -d",
"compose:build": "npm run compose -- build",
"compose:build:no-cache": "npm run compose -- build --no-cache",
"compose:build-and-up": "npx npm-run-all --sequential compose:build compose:up",
"compose:build-no-cache-and-up": "npx npm-run-all --sequential compose:build:no-cache compose:up",
"compose:down": "npm run compose -- down",
"compose:ps": "npm run compose -- ps -a",
"compose": "docker compose",
"config": "./.dotfiles/config.sh",
"update:submodules": "git submodule foreach --recursive 'branch=$(git remote show origin | awk \"/HEAD branch/ {print \\$NF}\"); git checkout $branch && git pull origin $branch' && CHANGED=$(git status --porcelain | grep '^ M \\.dotfiles' || true) && if [ -n \"$CHANGED\" ]; then npm run config; fi && git add -A && git commit -m \"chore: update submodules\" || echo 'No changes to commit'"
},
Expand Down
Loading