Skip to content

Commit 3ea5660

Browse files
authored
Merge pull request #5390 from woocommerce/issue/5300-card-reader-software-update-tracks-properties
[Mobile Payments] Card reader software update Tracks properties
2 parents 5fdfe29 + 7bcbecf commit 3ea5660

File tree

6 files changed

+74
-14
lines changed

6 files changed

+74
-14
lines changed

WooCommerce/Classes/ViewRelated/CardPresentPayments/CardReaderConnectionController.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,9 +407,13 @@ private extension CardReaderConnectionController {
407407
let cancel = softwareUpdateCancelable.map { cancelable in
408408
return { [weak self] in
409409
self?.state = .cancel
410+
let analyticsProperties = [SoftwareUpdateTypeProperty.name: SoftwareUpdateTypeProperty.required.rawValue]
411+
ServiceLocator.analytics.track(.cardReaderSoftwareUpdateCancelTapped, withProperties: analyticsProperties)
410412
cancelable.cancel { result in
411413
if case .failure(let error) = result {
412414
print("=== error canceling software update: \(error)")
415+
} else {
416+
ServiceLocator.analytics.track(.cardReaderSoftwareUpdateCanceled, withProperties: analyticsProperties)
413417
}
414418
}
415419
}

WooCommerce/Classes/ViewRelated/Dashboard/Settings/CardReadersV2/CardReaderSettingsConnectedViewModel.swift

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ final class CardReaderSettingsConnectedViewModel: CardReaderSettingsPresentedVie
6464
self.readerUpdateError = nil
6565
self.softwareUpdateCancelable = cancelable
6666
self.readerUpdateProgress = 0
67-
ServiceLocator.analytics.track(.cardReaderSoftwareUpdateStarted)
67+
self.track(.cardReaderSoftwareUpdateStarted)
6868
case .installing(progress: let progress):
6969
self.readerUpdateProgress = progress
7070
case .failed(error: let error):
@@ -74,12 +74,12 @@ final class CardReaderSettingsConnectedViewModel: CardReaderSettingsPresentedVie
7474
break
7575
}
7676
self.readerUpdateError = error
77+
self.track(.cardReaderSoftwareUpdateFailed, error: error)
7778
self.completeCardReaderUpdate(success: false)
78-
ServiceLocator.analytics.track(.cardReaderSoftwareUpdateFailed)
7979
case .completed:
8080
self.readerUpdateProgress = 1
8181
self.softwareUpdateCancelable = nil
82-
ServiceLocator.analytics.track(.cardReaderSoftwareUpdateSuccess)
82+
self.track(.cardReaderSoftwareUpdateSuccess)
8383
// If we were installing a software update, introduce a small delay so the user can
8484
// actually see a success message showing the installation was complete
8585
DispatchQueue.main.asyncAfter(deadline: .now() + self.delayToShowUpdateSuccessMessage) { [weak self] in
@@ -130,19 +130,19 @@ final class CardReaderSettingsConnectedViewModel: CardReaderSettingsPresentedVie
130130
/// Allows the view controller to kick off a card reader update
131131
///
132132
func startCardReaderUpdate() {
133-
ServiceLocator.analytics.track(.cardReaderSoftwareUpdateTapped)
133+
track(.cardReaderSoftwareUpdateTapped)
134134
let action = CardPresentPaymentAction.startCardReaderUpdate
135135
ServiceLocator.stores.dispatch(action)
136136
}
137137

138138
func cancelCardReaderUpdate() {
139-
ServiceLocator.analytics.track(.cardReaderSoftwareUpdateCancelTapped)
139+
track(.cardReaderSoftwareUpdateCancelTapped)
140140
softwareUpdateCancelable?.cancel(completion: { [weak self] result in
141141
if case .failure(let error) = result {
142142
print("=== error canceling software update: \(error)")
143143
} else {
144+
self?.track(.cardReaderSoftwareUpdateCanceled)
144145
self?.completeCardReaderUpdate(success: false)
145-
ServiceLocator.analytics.track(.cardReaderSoftwareUpdateCanceled)
146146
}
147147
})
148148
}
@@ -162,7 +162,7 @@ final class CardReaderSettingsConnectedViewModel: CardReaderSettingsPresentedVie
162162
/// Dispatch a request to disconnect from a reader
163163
///
164164
func disconnectReader() {
165-
ServiceLocator.analytics.track(.cardReaderDisconnectTapped)
165+
track(.cardReaderDisconnectTapped)
166166

167167
self.readerDisconnectInProgress = true
168168
self.didUpdate?()
@@ -203,6 +203,11 @@ final class CardReaderSettingsConnectedViewModel: CardReaderSettingsPresentedVie
203203
didChangeShouldShow?(shouldShow)
204204
}
205205
}
206+
207+
private func track(_ stat: WooAnalyticsStat, error: Error? = nil) {
208+
let updateType = optionalReaderUpdateAvailable ? SoftwareUpdateTypeProperty.optional : SoftwareUpdateTypeProperty.required
209+
ServiceLocator.analytics.track(stat, properties: [SoftwareUpdateTypeProperty.name: updateType.rawValue], error: error)
210+
}
206211
}
207212

208213
// MARK: - Localization
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
enum SoftwareUpdateTypeProperty: String {
2+
case optional = "Optional"
3+
case required = "Required"
4+
5+
static let name = "software_update_type"
6+
}

WooCommerce/WooCommerce.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,7 @@
375375
02F6800925807CD300C3BAD2 /* GridStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02F6800825807CD300C3BAD2 /* GridStackView.swift */; };
376376
02F843DA273646A30017FE12 /* JetpackBenefitsBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02F843D9273646A30017FE12 /* JetpackBenefitsBanner.swift */; };
377377
02FE89C7231FAA4100E85EF8 /* MainTabBarControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02FE89C6231FAA4100E85EF8 /* MainTabBarControllerTests.swift */; };
378+
035C6DEB273EA12D00F70406 /* SoftwareUpdateTypeProperty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035C6DEA273EA12D00F70406 /* SoftwareUpdateTypeProperty.swift */; };
378379
03AA165E2719B7EF005CCB7B /* ReceiptActionCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03AA165D2719B7EF005CCB7B /* ReceiptActionCoordinator.swift */; };
379380
03AA16602719B83D005CCB7B /* ReceiptActionCoordinatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03AA165F2719B83D005CCB7B /* ReceiptActionCoordinatorTests.swift */; };
380381
247CE89C2583402A00F9D9D1 /* Embassy in Frameworks */ = {isa = PBXBuildFile; productRef = 247CE89B2583402A00F9D9D1 /* Embassy */; };
@@ -1846,6 +1847,7 @@
18461847
02F6800825807CD300C3BAD2 /* GridStackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GridStackView.swift; sourceTree = "<group>"; };
18471848
02F843D9273646A30017FE12 /* JetpackBenefitsBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackBenefitsBanner.swift; sourceTree = "<group>"; };
18481849
02FE89C6231FAA4100E85EF8 /* MainTabBarControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabBarControllerTests.swift; sourceTree = "<group>"; };
1850+
035C6DEA273EA12D00F70406 /* SoftwareUpdateTypeProperty.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoftwareUpdateTypeProperty.swift; sourceTree = "<group>"; };
18491851
03AA165D2719B7EF005CCB7B /* ReceiptActionCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReceiptActionCoordinator.swift; sourceTree = "<group>"; };
18501852
03AA165F2719B83D005CCB7B /* ReceiptActionCoordinatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReceiptActionCoordinatorTests.swift; sourceTree = "<group>"; };
18511853
247CE8A5258340E600F9D9D1 /* ScreenshotImages.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = ScreenshotImages.xcassets; sourceTree = "<group>"; };
@@ -4167,6 +4169,7 @@
41674169
311F827326CD897900DF5BAD /* CardReaderSettingsAlertsProvider.swift */,
41684170
311D21EC264AF0E700102316 /* CardReaderSettingsAlerts.swift */,
41694171
3178C1F626409216000D771A /* CardReaderSettingsConnectedViewModel.swift */,
4172+
035C6DEA273EA12D00F70406 /* SoftwareUpdateTypeProperty.swift */,
41704173
314265B02645A07800500598 /* CardReaderSettingsConnectedViewController.swift */,
41714174
3188533B2639FE5800F66A9C /* CardReaderSettingsPresentedViewViewModel.swift */,
41724175
318853352639FC9C00F66A9C /* CardReaderSettingsPresentingViewController.swift */,
@@ -7518,6 +7521,7 @@
75187521
B59D1EEA2190AE96009D1978 /* StorageNote+Woo.swift in Sources */,
75197522
024DF3072372C18D006658FE /* AztecUIConfigurator.swift in Sources */,
75207523
020BE74823B05CF2007FE54C /* ProductInventoryEditableData.swift in Sources */,
7524+
035C6DEB273EA12D00F70406 /* SoftwareUpdateTypeProperty.swift in Sources */,
75217525
31F92DE125E85F6A00DE04DF /* ConnectedReaderTableViewCell.swift in Sources */,
75227526
26C6E8E026E2B7BD00C7BB0F /* CountrySelectorViewModel.swift in Sources */,
75237527
0285BF7022FBD91C003A2525 /* TopPerformersSectionHeaderView.swift in Sources */,

WooCommerce/WooCommerceTests/Mocks/MockAnalyticsProvider.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,17 @@ public extension MockAnalyticsProvider {
6363
// no op
6464
}
6565
}
66+
67+
// MARK: - Convenience Keys
68+
extension MockAnalyticsProvider {
69+
/// WooAnalyticsKeys
70+
/// Canonically defined in WooAnalytics.swift
71+
enum WooAnalyticsKeys {
72+
static let errorKeyCode = "error_code"
73+
static let errorKeyDomain = "error_domain"
74+
static let errorKeyDescription = "error_description"
75+
static let propertyKeyTimeInApp = "time_in_app"
76+
static let blogIDKey = "blog_id"
77+
static let wpcomStoreKey = "is_wpcom_store"
78+
}
79+
}

WooCommerce/WooCommerceTests/ViewRelated/Dashboard/CardReaderSettings/CardReaderSettingsConnectedViewModelTests.swift

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ final class CardReaderSettingsConnectedViewModelTests: XCTestCase {
156156
wait(for: [expectation], timeout: Constants.expectationTimeout)
157157
}
158158

159-
func test_startCardReaderUpdate_ViewModel_LogsTracksEvent_cardReaderSoftwareUpdateTapped() {
159+
func test_startCardReaderUpdate_viewModel_logs_tracks_event_cardReaderSoftwareUpdateTapped() {
160160
// Given
161161

162162
// When
@@ -166,17 +166,35 @@ final class CardReaderSettingsConnectedViewModelTests: XCTestCase {
166166
XCTAssert(analytics.receivedEvents.contains(WooAnalyticsStat.cardReaderSoftwareUpdateTapped.rawValue))
167167
}
168168

169-
func test_startCardReaderUpdate_ViewModel_LogsTracksEvent_cardReaderSoftwareUpdateStarted() {
169+
func test_card_reader_update_starts_viewModel_logs_tracks_event_cardReaderSoftwareUpdateStarted() {
170170
// Given
171+
// .available not sent
171172

172173
// When
173174
mockStoresManager.simulateUpdateStarted()
174175

175176
// Then
176177
XCTAssert(analytics.receivedEvents.contains(WooAnalyticsStat.cardReaderSoftwareUpdateStarted.rawValue))
178+
XCTAssert(analytics.receivedProperties.contains(where: {
179+
$0["software_update_type"] as? String == "Required"
180+
}))
177181
}
178182

179-
func test_WhenStoreSendsUpdateComplete_ViewModel_LogsTracksEvent_cardReaderSoftwareUpdateSuccess() {
183+
func test_optional_card_reader_update_starts_viewModel_logs_tracks_event_cardReaderSoftwareUpdateStarted_with_optional() {
184+
// Given
185+
mockStoresManager.simulateOptionalUpdateAvailable()
186+
187+
// When
188+
mockStoresManager.simulateUpdateStarted()
189+
190+
// Then
191+
XCTAssert(analytics.receivedEvents.contains(WooAnalyticsStat.cardReaderSoftwareUpdateStarted.rawValue))
192+
XCTAssert(analytics.receivedProperties.contains(where: {
193+
$0["software_update_type"] as? String == "Optional"
194+
}))
195+
}
196+
197+
func test_when_store_sends_update_complete_viewModel_logs_tracks_event_cardReaderSoftwareUpdateSuccess() {
180198
// Given
181199

182200
// When
@@ -186,19 +204,28 @@ final class CardReaderSettingsConnectedViewModelTests: XCTestCase {
186204
XCTAssert(analytics.receivedEvents.contains(WooAnalyticsStat.cardReaderSoftwareUpdateSuccess.rawValue))
187205
}
188206

189-
func test_WhenStoreSendsUpdateFailed_ViewModel_LogsTracksEvent_cardReaderSoftwareUpdateFailed() {
207+
func test_when_store_sends_update_failed_viewModel_logs_tracks_event_cardReaderSoftwareUpdateFailed() {
190208
// Given
209+
// .available not sent
191210

192211
// When
193212
let expectedError = CardReaderServiceError.softwareUpdate(underlyingError: .readerSoftwareUpdateFailedBatteryLow,
194213
batteryLevel: 0.4)
195214
mockStoresManager.simulateFailedUpdate(error: expectedError)
196215

197216
// Then
217+
let expectedErrorDescription = "Hardware.CardReaderServiceError.softwareUpdate(underlyingError: " +
218+
"Hardware.UnderlyingError.readerSoftwareUpdateFailedBatteryLow, batteryLevel: Optional(0.4))"
198219
XCTAssert(analytics.receivedEvents.contains(WooAnalyticsStat.cardReaderSoftwareUpdateFailed.rawValue))
220+
XCTAssert(analytics.receivedProperties.contains(where: {
221+
$0["software_update_type"] as? String == "Required"
222+
}))
223+
XCTAssert(analytics.receivedProperties.contains(where: {
224+
$0[MockAnalyticsProvider.WooAnalyticsKeys.errorKeyDescription] as? String == expectedErrorDescription
225+
}))
199226
}
200227

201-
func test_WhenUserCancelsUpdate_ViewModel_LogsTracksEvent_cardReaderSoftwareUpdateCancelTapped() {
228+
func test_when_user_cancels_update_viewModel_logs_tracks_event_cardReaderSoftwareUpdateCancelTapped() {
202229
// Given
203230

204231
// When
@@ -208,7 +235,7 @@ final class CardReaderSettingsConnectedViewModelTests: XCTestCase {
208235
XCTAssert(analytics.receivedEvents.contains(WooAnalyticsStat.cardReaderSoftwareUpdateCancelTapped.rawValue))
209236
}
210237

211-
func test_WhenUpdateIsSuccessfullyCanceled_ViewModel_LogsTracksEvent_cardReaderSoftwareUpdateCanceled() {
238+
func test_when_update_is_successfully_canceled_viewModel_logs_tracks_event_cardReaderSoftwareUpdateCanceled() {
212239
// Given
213240
let expectation = self.expectation(description: #function)
214241

@@ -224,7 +251,7 @@ final class CardReaderSettingsConnectedViewModelTests: XCTestCase {
224251
XCTAssert(analytics.receivedEvents.contains(WooAnalyticsStat.cardReaderSoftwareUpdateCanceled.rawValue))
225252
}
226253

227-
func test_WhenUpdateIsSuccessfullyCanceled_ViewModel_DoesNotLogTracksEvent_cardReaderSoftwareUpdateFailed() {
254+
func test_when_update_is_successfully_canceled_viewModel_does_not_log_tracks_event_cardReaderSoftwareUpdateFailed() {
228255
// Given
229256
let expectation = self.expectation(description: #function)
230257

0 commit comments

Comments
 (0)