Skip to content

Commit 24f495b

Browse files
Introduce Keys.sequence (#164)
1 parent eda2f0d commit 24f495b

File tree

6 files changed

+36
-57
lines changed

6 files changed

+36
-57
lines changed

Sources/WebDriver/Element.swift

-7
Original file line numberDiff line numberDiff line change
@@ -107,13 +107,6 @@ public struct Element {
107107
session: session.id, element: id, attribute: name)).value
108108
}
109109

110-
/// Sends key presses to this element.
111-
/// - Parameter keys: An array of key sequences according to the WebDriver spec.
112-
public func sendKeys(_ keys: [Keys]) throws {
113-
try webDriver.send(Requests.ElementValue(
114-
session: session.id, element: id, value: keys.map { $0.rawValue }))
115-
}
116-
117110
/// Sends key presses to this element.
118111
/// - Parameter keys: A key sequence according to the WebDriver spec.
119112
public func sendKeys(_ keys: Keys) throws {

Sources/WebDriver/Keys.swift

+20-25
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,23 @@
11
/// Represents a sequence of WebDriver key events and characters.
22
public struct Keys: RawRepresentable {
3+
/// A string encoding the key sequence as defined by the WebDriver spec.
34
public var rawValue: String
45

56
public init(rawValue: String) { self.rawValue = rawValue }
67

7-
public static func +(lhs: Self, rhs: Self) -> Self { Self(rawValue: lhs.rawValue + rhs.rawValue) }
8+
/// Concatenates multiple key sequences into a single one.
9+
public static func sequence(_ keys: [Self]) -> Self {
10+
Self(rawValue: keys.reduce("") { $0 + $1.rawValue })
11+
}
12+
13+
/// Concatenates multiple key sequences into a single one.
14+
public static func sequence(_ keys: Self...) -> Self {
15+
sequence(keys)
16+
}
17+
}
818

19+
// MARK: Key constants
20+
extension Keys {
921
public static let a = Self(rawValue: "a")
1022
public static let b = Self(rawValue: "b")
1123
public static let c = Self(rawValue: "c")
@@ -109,47 +121,30 @@ public struct Keys: RawRepresentable {
109121
public static let releaseModifiers = Keys(rawValue: "\u{E000}")
110122
}
111123

124+
// MARK: Modifier sequences
112125
extension Keys {
113126
/// Wraps a keys sequence with holding and releasing the shift key.
114127
public static func shift(_ keys: Self) -> Self {
115-
Self(rawValue: "\(shiftModifier.rawValue)\(keys.rawValue)\(shiftModifier.rawValue)")
128+
sequence(shiftModifier, keys, shiftModifier)
116129
}
117130

118131
/// Wraps a keys sequence with holding and releasing the control key.
119132
public static func control(_ keys: Self) -> Self {
120-
Self(rawValue: "\(controlModifier.rawValue)\(keys.rawValue)\(controlModifier.rawValue)")
133+
sequence(controlModifier, keys, controlModifier)
121134
}
122135

123136
/// Wraps a keys sequence with holding and releasing the alt key.
124137
public static func alt(_ keys: Self) -> Self {
125-
Self(rawValue: "\(altModifier.rawValue)\(keys.rawValue)\(altModifier.rawValue)")
138+
sequence(altModifier, keys, altModifier)
126139
}
127140

128141
/// Wraps a keys sequence with holding and releasing the meta key.
129142
public static func meta(_ keys: Self) -> Self {
130-
Self(rawValue: "\(metaModifier.rawValue)\(keys.rawValue)\(metaModifier.rawValue)")
131-
}
132-
133-
/// Wraps a keys sequence with holding and releasing modifier keys.
134-
public static func combo(_ keys: Self, shift: Bool = false, control: Bool = false, alt: Bool = false, meta: Bool = false) -> Self {
135-
var rawValue = ""
136-
137-
if shift { rawValue += shiftModifier.rawValue }
138-
if control { rawValue += controlModifier.rawValue }
139-
if alt { rawValue += altModifier.rawValue }
140-
if meta { rawValue += metaModifier.rawValue }
141-
142-
rawValue += keys.rawValue
143-
144-
if meta { rawValue += metaModifier.rawValue }
145-
if alt { rawValue += altModifier.rawValue }
146-
if control { rawValue += controlModifier.rawValue }
147-
if shift { rawValue += shiftModifier.rawValue }
148-
149-
return Self(rawValue: rawValue)
143+
sequence(metaModifier, keys, metaModifier)
150144
}
151145
}
152146

147+
// MARK: Text and typing
153148
extension Keys {
154149
public enum TypingStrategy {
155150
case assumeUSKeyboard
@@ -210,4 +205,4 @@ extension Keys {
210205
default: return false
211206
}
212207
}
213-
}
208+
}

Sources/WebDriver/Session.swift

-9
Original file line numberDiff line numberDiff line change
@@ -282,15 +282,6 @@ public class Session {
282282
session: id, element: element?.id, xOffset: xOffset, yOffset: yOffset))
283283
}
284284

285-
/// Sends key presses to this session.
286-
/// - Parameter keys: An array of key sequences according to the WebDriver spec.
287-
/// - Parameter releaseModifiers: A boolean indicating whether to release modifier keys at the end of the sequence.
288-
public func sendKeys(_ keys: [Keys], releaseModifiers: Bool = true) throws {
289-
var value = keys.map { $0.rawValue }
290-
if releaseModifiers { value.append(Keys.releaseModifiers.rawValue) }
291-
try webDriver.send(Requests.SessionKeys(session: id, value: value))
292-
}
293-
294285
/// Sends key presses to this session.
295286
/// - Parameter keys: A key sequence according to the WebDriver spec.
296287
/// - Parameter releaseModifiers: A boolean indicating whether to release modifier keys at the end of the sequence.

Tests/UnitTests/APIToRequestMappingTests.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -123,15 +123,15 @@ class APIToRequestMappingTests: XCTestCase {
123123
let session = Session(webDriver: mockWebDriver, existingId: "mySession")
124124
let element = Element(session: session, id: "myElement")
125125

126-
let keys = [ Keys.a, Keys.b, Keys.c ]
126+
let keys = Keys.sequence(.a, .b, .c)
127127
mockWebDriver.expect(path: "session/mySession/keys", method: .post, type: Requests.SessionKeys.self) {
128-
XCTAssertEqual($0.value, keys.map { $0.rawValue })
128+
XCTAssertEqual($0.value.first, keys.rawValue)
129129
return CodableNone()
130130
}
131131
try session.sendKeys(keys, releaseModifiers: false)
132132

133133
mockWebDriver.expect(path: "session/mySession/element/myElement/value", method: .post, type: Requests.ElementValue.self) {
134-
XCTAssertEqual($0.value, keys.map { $0.rawValue })
134+
XCTAssertEqual($0.value.first, keys.rawValue)
135135
return CodableNone()
136136
}
137137
try element.sendKeys(keys)

Tests/WinAppDriverTests/MSInfo32App.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
import XCTest
33

44
class MSInfo32App {
5-
static let findWhatEditBoxAccelerator = Keys.alt(Keys.w)
6-
static let searchSelectedCategoryOnlyCheckboxAccelerator = Keys.alt(Keys.s)
5+
static let findWhatEditBoxAccelerator = Keys.alt(.w)
6+
static let searchSelectedCategoryOnlyCheckboxAccelerator = Keys.alt(.s)
77

88
let session: Session
99

Tests/WinAppDriverTests/RequestsTests.swift

+11-11
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ class RequestsTests: XCTestCase {
8282
// ł: Not typeable on a US Keyboard
8383
// ☃: Unicode BMP character
8484
let str = "kKł☃"
85-
try app.findWhatEditBox.sendKeys(Keys.text(str, typingStrategy: .windowsKeyboardAgnostic))
85+
try app.findWhatEditBox.sendKeys(.text(str, typingStrategy: .windowsKeyboardAgnostic))
8686

8787
// Normally we should be able to read the text back immediately,
8888
// but the MSInfo32 "Find what" edit box seems to queue events
@@ -97,40 +97,40 @@ class RequestsTests: XCTestCase {
9797
func testSendKeysWithAcceleratorsGivesFocus() throws {
9898
try app.session.sendKeys(MSInfo32App.findWhatEditBoxAccelerator)
9999
try XCTAssert(Self.hasKeyboardFocus(app.findWhatEditBox))
100-
try app.session.sendKeys(Keys.tab)
100+
try app.session.sendKeys(.tab)
101101
try XCTAssert(!Self.hasKeyboardFocus(app.findWhatEditBox))
102102
}
103103

104104
func testSessionSendKeys_scopedModifiers() throws {
105105
try app.findWhatEditBox.click()
106-
try app.session.sendKeys(Keys.shift(Keys.a) + Keys.a)
106+
try app.session.sendKeys(.sequence(.shift(.a), .a))
107107
XCTAssertEqual(try app.findWhatEditBox.text, "Aa")
108108
}
109109

110110
func testSessionSendKeys_autoReleasedModifiers() throws {
111111
try app.findWhatEditBox.click()
112-
try app.session.sendKeys(Keys.shiftModifier + Keys.a)
113-
try app.session.sendKeys(Keys.a)
112+
try app.session.sendKeys(.sequence(.shiftModifier, .a))
113+
try app.session.sendKeys(.a)
114114
XCTAssertEqual(try app.findWhatEditBox.text, "Aa")
115115
}
116116

117117
func testSessionSendKeys_stickyModifiers() throws {
118118
try app.findWhatEditBox.click()
119-
try app.session.sendKeys(Keys.shiftModifier + Keys.a, releaseModifiers: false)
120-
try app.session.sendKeys(Keys.a)
119+
try app.session.sendKeys(.sequence(.shiftModifier, .a), releaseModifiers: false)
120+
try app.session.sendKeys(.a)
121121
try app.session.sendKeys(.releaseModifiers)
122-
try app.session.sendKeys(Keys.a)
122+
try app.session.sendKeys(.a)
123123
XCTAssertEqual(try app.findWhatEditBox.text, "AAa")
124124
}
125125

126126
func testElementSendKeys_scopedModifiers() throws {
127-
try app.findWhatEditBox.sendKeys(Keys.shift(Keys.a) + Keys.a)
127+
try app.findWhatEditBox.sendKeys(.sequence(.shift(.a), .a))
128128
XCTAssertEqual(try app.findWhatEditBox.text, "Aa")
129129
}
130130

131131
func testElementSendKeys_autoReleasedModifiers() throws {
132-
try app.findWhatEditBox.sendKeys(Keys.shiftModifier + Keys.a)
133-
try app.findWhatEditBox.sendKeys(Keys.a)
132+
try app.findWhatEditBox.sendKeys(.sequence(.shiftModifier, .a))
133+
try app.findWhatEditBox.sendKeys(.a)
134134
XCTAssertEqual(try app.findWhatEditBox.text, "Aa")
135135
}
136136

0 commit comments

Comments
 (0)