Skip to content

Commit 0db9ef0

Browse files
committed
Add associated value for connection error, expand unit tests
1 parent a44cbf3 commit 0db9ef0

File tree

4 files changed

+108
-10
lines changed

4 files changed

+108
-10
lines changed

WooCommerce/Classes/ViewRelated/CardPresentPayments/CardReaderConnectionController.swift

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ final class CardReaderConnectionController {
3636
/// A failure occurred while connecting. The search may continue or be canceled. At this time we
3737
/// do not present the detailed error from the service.
3838
///
39-
case connectingFailed
39+
case connectingFailed(Error)
4040

4141
/// User cancelled search/connecting to a card reader. The completion passed to `searchAndConnect`
4242
/// will be called with a `success` `Bool` `False` result. The view controller passed to `searchAndConnect` will be
@@ -127,8 +127,8 @@ private extension CardReaderConnectionController {
127127
onCancel()
128128
case .connectToReader:
129129
onConnectToReader()
130-
case .connectingFailed:
131-
onConnectingFailed()
130+
case .connectingFailed(let error):
131+
onConnectingFailed(error: error)
132132
case .discoveryFailed(let error):
133133
onDiscoveryFailed(error: error)
134134
}
@@ -319,7 +319,7 @@ private extension CardReaderConnectionController {
319319
self.returnSuccess(connected: true)
320320
case .failure(let error):
321321
ServiceLocator.analytics.track(.cardReaderConnectionFailed, withError: error)
322-
self.state = .connectingFailed
322+
self.state = .connectingFailed(error)
323323
}
324324
}
325325
ServiceLocator.stores.dispatch(action)
@@ -329,13 +329,14 @@ private extension CardReaderConnectionController {
329329

330330
/// An error occurred while connecting
331331
///
332-
private func onConnectingFailed() {
332+
private func onConnectingFailed(error: Error) {
333333
guard let from = fromController else {
334334
return
335335
}
336336

337-
/// Let's start over again - we don't want to try and connect to something obviously borked
338-
/// right off the bat
337+
/// Clear our copy of found readers to avoid connecting to a reader that isn't
338+
/// there while we wait for `onReaderDiscovered` to receive an update.
339+
/// See also https://github.com/stripe/stripe-terminal-ios/issues/104#issuecomment-916285167
339340
///
340341
self.foundReaders = []
341342

WooCommerce/WooCommerceTests/Mocks/MockCardPresentPaymentsStoresManager.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,24 @@ final class MockCardPresentPaymentsStoresManager: DefaultStoresManager {
1010
private var readerUpdateAvailable: Bool
1111
private var failReaderUpdateCheck: Bool
1212
private var failUpdate: Bool
13+
private var failConnection: Bool
1314

1415
init(connectedReaders: [CardReader],
1516
discoveredReader: CardReader? = nil,
1617
sessionManager: SessionManager,
1718
failDiscovery: Bool = false,
1819
readerUpdateAvailable: Bool = false,
1920
failReaderUpdateCheck: Bool = false,
20-
failUpdate: Bool = false
21+
failUpdate: Bool = false,
22+
failConnection: Bool = false
2123
) {
2224
self.connectedReaders = connectedReaders
2325
self.discoveredReader = discoveredReader
2426
self.failDiscovery = failDiscovery
2527
self.readerUpdateAvailable = readerUpdateAvailable
2628
self.failReaderUpdateCheck = failReaderUpdateCheck
2729
self.failUpdate = failUpdate
30+
self.failConnection = failConnection
2831
super.init(sessionManager: sessionManager)
2932
}
3033

@@ -50,6 +53,10 @@ final class MockCardPresentPaymentsStoresManager: DefaultStoresManager {
5053
}
5154
onReaderDiscovered([discoveredReader])
5255
case .connect(let reader, let onCompletion):
56+
guard !failConnection else {
57+
onCompletion(Result.failure(MockErrors.connectionFailure))
58+
return
59+
}
5360
onCompletion(Result.success(reader))
5461
case .cancelCardReaderDiscovery(let onCompletion):
5562
onCompletion(Result.success(()))
@@ -81,6 +88,7 @@ extension MockCardPresentPaymentsStoresManager {
8188
case discoveryFailure
8289
case readerUpdateCheckFailure
8390
case readerUpdateFailure
91+
case connectionFailure
8492
}
8593
}
8694

WooCommerce/WooCommerceTests/Mocks/MockCardReaderSettingsAlerts.swift

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,30 @@ enum MockCardReaderSettingsAlertsMode {
77
case closeScanFailure
88
case continueSearching
99
case connectFoundReader
10+
case continueSearchingAfterConnectionFailure
11+
case cancelSearchingAfterConnectionFailure
1012
}
1113

1214
final class MockCardReaderSettingsAlerts: CardReaderSettingsAlertsProvider {
1315
private var mode: MockCardReaderSettingsAlertsMode
16+
private var didPresentFoundReader: Bool
1417

1518
init(mode: MockCardReaderSettingsAlertsMode) {
1619
self.mode = mode
20+
self.didPresentFoundReader = false
1721
}
1822
func scanningForReader(from: UIViewController, cancel: @escaping () -> Void) {
1923
if mode == .cancelScanning {
2024
cancel()
2125
}
26+
27+
if mode == .continueSearchingAfterConnectionFailure {
28+
/// If we've already presented a found reader once before, cancel this second search
29+
///
30+
if didPresentFoundReader {
31+
cancel()
32+
}
33+
}
2234
}
2335

2436
func scanningFailed(from: UIViewController, error: Error, close: @escaping () -> Void) {
@@ -28,11 +40,13 @@ final class MockCardReaderSettingsAlerts: CardReaderSettingsAlertsProvider {
2840
}
2941

3042
func foundReader(from: UIViewController, name: String, connect: @escaping () -> Void, continueSearch: @escaping () -> Void) {
43+
didPresentFoundReader = true
44+
3145
if mode == .continueSearching {
3246
continueSearch()
3347
}
3448

35-
if mode == .connectFoundReader {
49+
if mode == .connectFoundReader || mode == .cancelSearchingAfterConnectionFailure || mode == .continueSearchingAfterConnectionFailure {
3650
connect()
3751
}
3852
}
@@ -42,7 +56,13 @@ final class MockCardReaderSettingsAlerts: CardReaderSettingsAlertsProvider {
4256
}
4357

4458
func connectingFailed(from: UIViewController, continueSearch: @escaping () -> Void, cancelSearch: @escaping () -> Void) {
45-
// GNDN
59+
if mode == .continueSearchingAfterConnectionFailure {
60+
continueSearch()
61+
}
62+
63+
if mode == .cancelSearchingAfterConnectionFailure {
64+
cancelSearch()
65+
}
4666
}
4767

4868
func dismiss() {

WooCommerce/WooCommerceTests/ViewRelated/CardPresentPayments/CardReaderConnectionControllerTests.swift

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,4 +134,73 @@ class CardReaderConnectionControllerTests: XCTestCase {
134134
wait(for: [expectation], timeout: Constants.expectationTimeout)
135135
}
136136

137+
func test_user_can_cancel_search_after_connection_error() {
138+
// Given
139+
let expectation = self.expectation(description: #function)
140+
141+
let discoveredReader = MockCardReader.bbposChipper2XBT()
142+
143+
let mockStoresManager = MockCardPresentPaymentsStoresManager(
144+
connectedReaders: [],
145+
discoveredReader: discoveredReader,
146+
sessionManager: SessionManager.testingInstance,
147+
failConnection: true
148+
)
149+
ServiceLocator.setStores(mockStoresManager)
150+
let mockPresentingViewController = UIViewController()
151+
let mockKnownReadersProvider = MockKnownReadersProvider(knownReaders: [])
152+
let mockAlerts = MockCardReaderSettingsAlerts(mode: .cancelSearchingAfterConnectionFailure)
153+
let controller = CardReaderConnectionController(
154+
forSiteID: sampleSiteID,
155+
knownReadersProvider: mockKnownReadersProvider,
156+
alertsProvider: mockAlerts
157+
)
158+
159+
// When
160+
controller.searchAndConnect(from: mockPresentingViewController) { result in
161+
XCTAssertTrue(result.isSuccess)
162+
if case .success(let connected) = result {
163+
XCTAssertFalse(connected)
164+
expectation.fulfill()
165+
}
166+
}
167+
168+
// Then
169+
wait(for: [expectation], timeout: Constants.expectationTimeout)
170+
}
171+
172+
func test_user_can_continue_search_after_connection_error() {
173+
// Given
174+
let expectation = self.expectation(description: #function)
175+
176+
let discoveredReader = MockCardReader.bbposChipper2XBT()
177+
178+
let mockStoresManager = MockCardPresentPaymentsStoresManager(
179+
connectedReaders: [],
180+
discoveredReader: discoveredReader,
181+
sessionManager: SessionManager.testingInstance,
182+
failConnection: true
183+
)
184+
ServiceLocator.setStores(mockStoresManager)
185+
let mockPresentingViewController = UIViewController()
186+
let mockKnownReadersProvider = MockKnownReadersProvider(knownReaders: [])
187+
let mockAlerts = MockCardReaderSettingsAlerts(mode: .continueSearchingAfterConnectionFailure)
188+
let controller = CardReaderConnectionController(
189+
forSiteID: sampleSiteID,
190+
knownReadersProvider: mockKnownReadersProvider,
191+
alertsProvider: mockAlerts
192+
)
193+
194+
// When
195+
controller.searchAndConnect(from: mockPresentingViewController) { result in
196+
XCTAssertTrue(result.isSuccess)
197+
if case .success(let connected) = result {
198+
XCTAssertFalse(connected)
199+
expectation.fulfill()
200+
}
201+
}
202+
203+
// Then
204+
wait(for: [expectation], timeout: Constants.expectationTimeout)
205+
}
137206
}

0 commit comments

Comments
 (0)