Skip to content

Commit eae2f57

Browse files
committed
Add and update tests for barcode scanner setup
- Update ScanTester tests for new callback structure - Add FlowManager tests for analytics tracking and state management - Test dismissal tracking behavior and completion step logic
1 parent 3b80b04 commit eae2f57

File tree

2 files changed

+188
-7
lines changed

2 files changed

+188
-7
lines changed
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
import Testing
2+
import Foundation
3+
import GameController
4+
@testable import WooCommerce
5+
6+
struct PointOfSaleBarcodeScannerSetupFlowManagerTests {
7+
8+
@available(iOS 17.0, *)
9+
@Test func test_flowManager_tracks_scanner_selected_when_selectScanner_called() {
10+
// Given a flow manager
11+
let mockAnalytics = MockAnalytics()
12+
let sut = PointOfSaleBarcodeScannerSetupFlowManager(
13+
isPresented: .constant(true),
14+
analytics: mockAnalytics
15+
)
16+
17+
// When a scanner is selected
18+
sut.selectScanner(.starBSH20B)
19+
20+
// Then it tracks the scanner selected event
21+
let event = mockAnalytics.events.first
22+
#expect(event?.eventName == WooAnalyticsStat.pointOfSaleBarcodeScannerSetupScannerSelected.rawValue)
23+
#expect(event?.properties["scanner"] as? String == "Star_BSH_20B")
24+
}
25+
26+
@available(iOS 17.0, *)
27+
@Test func test_flowManager_tracks_dismissal_when_onDisappear_called_on_non_completion_step() {
28+
// Given a flow manager with a setup flow in progress
29+
let mockAnalytics = MockAnalytics()
30+
let sut = PointOfSaleBarcodeScannerSetupFlowManager(
31+
isPresented: .constant(true),
32+
analytics: mockAnalytics
33+
)
34+
35+
// Setup a scanner flow (not on completion step)
36+
sut.selectScanner(.starBSH20B)
37+
mockAnalytics.events.removeAll() // Clear the selection event
38+
39+
// When onDisappear is called (not on completion step)
40+
sut.onDisappear()
41+
42+
// Then it tracks the dismissal event
43+
let event = mockAnalytics.events.first
44+
#expect(event?.eventName == WooAnalyticsStat.pointOfSaleBarcodeScannerSetupDismissed.rawValue)
45+
#expect(event?.properties["scanner"] as? String == "Star_BSH_20B")
46+
#expect(event?.properties["step"] as? String == "setup_barcode")
47+
}
48+
49+
@available(iOS 17.0, *)
50+
@Test func test_flowManager_tracks_dismissal_when_onDisappear_called_on_scanner_selection() {
51+
// Given a flow manager on scanner selection screen
52+
let mockAnalytics = MockAnalytics()
53+
let sut = PointOfSaleBarcodeScannerSetupFlowManager(
54+
isPresented: .constant(true),
55+
analytics: mockAnalytics
56+
)
57+
58+
// When onDisappear is called without selecting a scanner
59+
sut.onDisappear()
60+
61+
// Then it tracks the dismissal event without scanner info
62+
let event = mockAnalytics.events.first
63+
#expect(event?.eventName == WooAnalyticsStat.pointOfSaleBarcodeScannerSetupDismissed.rawValue)
64+
#expect(event?.properties["scanner"] == nil)
65+
#expect(event?.properties["step"] == nil)
66+
}
67+
68+
@available(iOS 17.0, *)
69+
@Test func test_flowManager_tracks_keyboard_connected_when_in_setup_flow() {
70+
// Given a flow manager with a setup flow
71+
let mockAnalytics = MockAnalytics()
72+
let sut = PointOfSaleBarcodeScannerSetupFlowManager(
73+
isPresented: .constant(true),
74+
analytics: mockAnalytics
75+
)
76+
77+
// Setup a scanner flow
78+
sut.selectScanner(.socketS720)
79+
mockAnalytics.events.removeAll() // Clear the selection event
80+
81+
// When keyboard connected notification is posted
82+
NotificationCenter.default.post(name: .GCKeyboardDidConnect, object: nil)
83+
84+
// Then it tracks the scanner connected event
85+
let event = mockAnalytics.events.first
86+
#expect(event?.eventName == WooAnalyticsStat.pointOfSaleBarcodeScannerSetupScannerConnected.rawValue)
87+
#expect(event?.properties["scanner"] as? String == "Socket_S720")
88+
}
89+
90+
@available(iOS 17.0, *)
91+
@Test func test_flowManager_does_not_track_keyboard_connected_when_on_scanner_selection() {
92+
// Given a flow manager on scanner selection
93+
let mockAnalytics = MockAnalytics()
94+
let sut = PointOfSaleBarcodeScannerSetupFlowManager(
95+
isPresented: .constant(true),
96+
analytics: mockAnalytics
97+
)
98+
99+
// When keyboard connected notification is posted
100+
NotificationCenter.default.post(name: .GCKeyboardDidConnect, object: nil)
101+
102+
// Then it does not track any scanner connected event
103+
#expect(mockAnalytics.events.isEmpty)
104+
}
105+
106+
@available(iOS 17.0, *)
107+
@Test func test_flowManager_returns_correct_state_after_scanner_selection() {
108+
// Given a flow manager
109+
let mockAnalytics = MockAnalytics()
110+
let sut = PointOfSaleBarcodeScannerSetupFlowManager(
111+
isPresented: .constant(true),
112+
analytics: mockAnalytics
113+
)
114+
115+
// Initially on scanner selection
116+
if case .scannerSelection = sut.currentState {
117+
// Expected state
118+
} else {
119+
#expect(Bool(false), "Expected scannerSelection state")
120+
}
121+
122+
// When a scanner is selected
123+
sut.selectScanner(.tbcScanner)
124+
125+
// Then state changes to setup flow
126+
if case .setupFlow(let scannerType) = sut.currentState {
127+
#expect(scannerType == .tbcScanner)
128+
} else {
129+
#expect(Bool(false), "Expected setupFlow state")
130+
}
131+
}
132+
133+
@available(iOS 17.0, *)
134+
@Test func test_flowManager_returns_to_scanner_selection_when_goBackToSelection_called() {
135+
// Given a flow manager in setup flow
136+
let mockAnalytics = MockAnalytics()
137+
let sut = PointOfSaleBarcodeScannerSetupFlowManager(
138+
isPresented: .constant(true),
139+
analytics: mockAnalytics
140+
)
141+
142+
sut.selectScanner(.other)
143+
if case .setupFlow = sut.currentState {
144+
// Expected state after selection
145+
} else {
146+
#expect(Bool(false), "Expected setupFlow state after selection")
147+
}
148+
149+
// When going back to selection
150+
sut.goBackToSelection()
151+
152+
// Then state returns to scanner selection
153+
if case .scannerSelection = sut.currentState {
154+
// Expected state after going back
155+
} else {
156+
#expect(Bool(false), "Expected scannerSelection state after going back")
157+
}
158+
#expect(sut.getCurrentStep() == nil)
159+
}
160+
}

WooCommerce/WooCommerceTests/POS/Presentation/Barcode Scanner Setup/PointOfSaleBarcodeScannerSetupScanTesterTests.swift

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ struct PointOfSaleBarcodeScannerSetupScanTesterTests {
88
let expectedBarcode = PointOfSaleBarcodeScannerTestBarcode.ean13
99
var onTestPassCalled = false
1010
var onTestFailureCalled = false
11+
var onTestTimeoutCalled = false
1112

1213
let sut = PointOfSaleBarcodeScannerSetupScanTester(
1314
onTestPass: { onTestPassCalled = true },
14-
onTestFailure: { onTestFailureCalled = true },
15+
onTestFailure: { _ in onTestFailureCalled = true },
16+
onTestTimeout: { onTestTimeoutCalled = true },
1517
barcodeDefinition: expectedBarcode)
1618

1719
// When the barcode is scanned
@@ -20,36 +22,52 @@ struct PointOfSaleBarcodeScannerSetupScanTesterTests {
2022
// Then it calls the pass closure
2123
#expect(onTestPassCalled == true)
2224
#expect(onTestFailureCalled == false)
25+
#expect(onTestTimeoutCalled == false)
2326
}
2427

2528
@Test func test_scanTester_calls_onTestFailure_when_scan_received_for_unexpected_barcode() {
2629
// Given a test EAN13 barcode
2730
let expectedBarcode = PointOfSaleBarcodeScannerTestBarcode.ean13
2831
var onTestPassCalled = false
2932
var onTestFailureCalled = false
33+
var onTestTimeoutCalled = false
34+
var receivedScanValue = ""
3035

3136
let sut = PointOfSaleBarcodeScannerSetupScanTester(
3237
onTestPass: { onTestPassCalled = true },
33-
onTestFailure: { onTestFailureCalled = true },
38+
onTestFailure: { scanValue in
39+
onTestFailureCalled = true
40+
receivedScanValue = scanValue
41+
},
42+
onTestTimeout: { onTestTimeoutCalled = true },
3443
barcodeDefinition: expectedBarcode)
3544

3645
// When an unexpected barcode is scanned
37-
sut.handleScan(.success("9999999999999"))
46+
let unexpectedBarcode = "9999999999999"
47+
sut.handleScan(.success(unexpectedBarcode))
3848

39-
// Then it calls the failure closure
49+
// Then it calls the failure closure with the scanned value
4050
#expect(onTestPassCalled == false)
4151
#expect(onTestFailureCalled == true)
52+
#expect(onTestTimeoutCalled == false)
53+
#expect(receivedScanValue == unexpectedBarcode)
4254
}
4355

44-
@Test func test_scanTester_calls_onTestFailure_when_scan_fails() {
56+
@Test func test_scanTester_calls_onTestFailure_when_scan_fails() {
4557
// Given a test EAN13 barcode
4658
let expectedBarcode = PointOfSaleBarcodeScannerTestBarcode.ean13
4759
var onTestPassCalled = false
4860
var onTestFailureCalled = false
61+
var onTestTimeoutCalled = false
62+
var receivedScanValue = ""
4963

5064
let sut = PointOfSaleBarcodeScannerSetupScanTester(
5165
onTestPass: { onTestPassCalled = true },
52-
onTestFailure: { onTestFailureCalled = true },
66+
onTestFailure: { scanValue in
67+
onTestFailureCalled = true
68+
receivedScanValue = scanValue
69+
},
70+
onTestTimeout: { onTestTimeoutCalled = true },
5371
barcodeDefinition: expectedBarcode)
5472

5573
// When the scan fails
@@ -58,6 +76,8 @@ struct PointOfSaleBarcodeScannerSetupScanTesterTests {
5876
// Then it calls the failure closure
5977
#expect(onTestPassCalled == false)
6078
#expect(onTestFailureCalled == true)
79+
#expect(onTestTimeoutCalled == false)
80+
#expect(receivedScanValue == "")
6181
}
6282

6383
private enum TestError: Error {
@@ -70,7 +90,8 @@ struct PointOfSaleBarcodeScannerSetupScanTesterTests {
7090

7191
let sut = PointOfSaleBarcodeScannerSetupScanTester(
7292
onTestPass: {},
73-
onTestFailure: {},
93+
onTestFailure: { _ in },
94+
onTestTimeout: {},
7495
barcodeDefinition: expectedBarcode)
7596

7697
// Then it provides the correct barcode asset

0 commit comments

Comments
 (0)