Skip to content

Commit 6060bee

Browse files
committed
7853 Track JITM GET request analytic events
1 parent d16587f commit 6060bee

File tree

4 files changed

+101
-16
lines changed

4 files changed

+101
-16
lines changed

WooCommerce/Classes/Analytics/WooAnalyticsEvent.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,8 +625,28 @@ extension WooAnalyticsEvent {
625625
enum JustInTimeMessage {
626626
private enum Keys {
627627
static let source = "source"
628+
static let justInTimeMessage = "jitm"
628629
static let justInTimeMessageID = "jitm_id"
629630
static let justInTimeMessageGroup = "jitm_group"
631+
static let count = "count"
632+
}
633+
634+
static func fetchSuccess(source: String,
635+
messageID: String,
636+
count: Int64) -> WooAnalyticsEvent {
637+
WooAnalyticsEvent(statName: .justInTimeMessageFetchSuccess,
638+
properties: [
639+
Keys.source: source,
640+
Keys.justInTimeMessage: messageID,
641+
Keys.count: count
642+
])
643+
}
644+
645+
static func fetchFailure(source: String,
646+
error: Error) -> WooAnalyticsEvent {
647+
WooAnalyticsEvent(statName: .justInTimeMessageFetchFailure,
648+
properties: [Keys.source: source],
649+
error: error)
630650
}
631651

632652
static func callToActionTapped(source: String,

WooCommerce/Classes/Analytics/WooAnalyticsStat.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,8 @@ public enum WooAnalyticsStat: String {
632632
case justInTimeMessageDismissTapped = "jitm_dismissed"
633633
case justInTimeMessageDismissSuccess = "jitm_dismiss_success"
634634
case justInTimeMessageDismissFailure = "jitm_dismiss_failure"
635+
case justInTimeMessageFetchSuccess = "jitm_fetch_success"
636+
case justInTimeMessageFetchFailure = "jitm_fetch_failure"
635637

636638
// MARK: Simple Payments events
637639
//

WooCommerce/Classes/ViewRelated/Dashboard/DashboardViewModel.swift

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,14 @@ final class DashboardViewModel {
1414

1515
private let stores: StoresManager
1616
private let featureFlagService: FeatureFlagService
17+
private let analytics: Analytics
1718

1819
init(stores: StoresManager = ServiceLocator.stores,
19-
featureFlags: FeatureFlagService = ServiceLocator.featureFlagService) {
20+
featureFlags: FeatureFlagService = ServiceLocator.featureFlagService,
21+
analytics: Analytics = ServiceLocator.analytics) {
2022
self.stores = stores
2123
self.featureFlagService = featureFlags
24+
self.analytics = analytics
2225
}
2326

2427
/// Syncs store stats for dashboard UI.
@@ -155,13 +158,21 @@ final class DashboardViewModel {
155158
guard let self = self else { return }
156159
switch result {
157160
case let .success(.some(message)):
161+
self.analytics.track(event:
162+
.JustInTimeMessage.fetchSuccess(source: Constants.dashboardScreenName,
163+
messageID: message.messageID,
164+
count: 1))
158165
let viewModel = JustInTimeMessageAnnouncementCardViewModel(
159166
justInTimeMessage: message,
160167
screenName: Constants.dashboardScreenName,
161168
siteID: siteID)
162169
self.announcementViewModel = viewModel
163170
viewModel.$showWebViewSheet.assign(to: &self.$showWebViewSheet)
164-
default:
171+
case let .failure(error):
172+
self.analytics.track(event:
173+
.JustInTimeMessage.fetchFailure(source: Constants.dashboardScreenName,
174+
error: error))
175+
case .success(.none):
165176
break
166177
}
167178
}

WooCommerce/WooCommerceTests/ViewRelated/Dashboard/DashboardViewModelTests.swift

Lines changed: 66 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@ import struct Yosemite.JustInTimeMessage
99
final class DashboardViewModelTests: XCTestCase {
1010
private let sampleSiteID: Int64 = 122
1111

12+
private var analytics: Analytics!
13+
private var analyticsProvider: MockAnalyticsProvider!
14+
private var stores: MockStoresManager!
15+
16+
override func setUp() {
17+
analyticsProvider = MockAnalyticsProvider()
18+
analytics = WooAnalytics(analyticsProvider: analyticsProvider)
19+
stores = MockStoresManager(sessionManager: .makeForTesting())
20+
}
21+
1222
func test_default_statsVersion_is_v4() {
1323
// Given
1424
let viewModel = DashboardViewModel()
@@ -19,7 +29,6 @@ final class DashboardViewModelTests: XCTestCase {
1929

2030
func test_statsVersion_changes_from_v4_to_v3_when_store_stats_sync_returns_noRestRoute_error() {
2131
// Given
22-
let stores = MockStoresManager(sessionManager: .makeForTesting())
2332
stores.whenReceivingAction(ofType: StatsActionV4.self) { action in
2433
if case let .retrieveStats(_, _, _, _, _, _, completion) = action {
2534
completion(.failure(DotcomError.noRestRoute))
@@ -37,7 +46,6 @@ final class DashboardViewModelTests: XCTestCase {
3746

3847
func test_statsVersion_remains_v4_when_non_store_stats_sync_returns_noRestRoute_error() {
3948
// Given
40-
let stores = MockStoresManager(sessionManager: .makeForTesting())
4149
stores.whenReceivingAction(ofType: StatsActionV4.self) { action in
4250
if case let .retrieveStats(_, _, _, _, _, _, completion) = action {
4351
completion(.failure(DotcomError.empty))
@@ -61,7 +69,6 @@ final class DashboardViewModelTests: XCTestCase {
6169

6270
func test_statsVersion_changes_from_v3_to_v4_when_store_stats_sync_returns_success() {
6371
// Given
64-
let stores = MockStoresManager(sessionManager: .makeForTesting())
6572
// `DotcomError.noRestRoute` error indicates the stats are unavailable.
6673
var storeStatsResult: Result<Void, Error> = .failure(DotcomError.noRestRoute)
6774
stores.whenReceivingAction(ofType: StatsActionV4.self) { action in
@@ -83,7 +90,6 @@ final class DashboardViewModelTests: XCTestCase {
8390

8491
func test_products_onboarding_announcements_take_precedence() {
8592
// Given
86-
let stores = MockStoresManager(sessionManager: .makeForTesting())
8793
stores.whenReceivingAction(ofType: ProductAction.self) { action in
8894
switch action {
8995
case let .checkProductsOnboardingEligibility(_, completion):
@@ -111,7 +117,18 @@ final class DashboardViewModelTests: XCTestCase {
111117

112118
func test_view_model_syncs_just_in_time_messages_when_ineligible_for_products_onboarding() {
113119
// Given
114-
let stores = MockStoresManager(sessionManager: .makeForTesting())
120+
let message = Yosemite.JustInTimeMessage.fake().copy(title: "JITM Message")
121+
prepareStoresToShowJustInTimeMessage(.success(message))
122+
let viewModel = DashboardViewModel(stores: stores)
123+
124+
// When
125+
viewModel.syncAnnouncements(for: sampleSiteID)
126+
127+
// Then
128+
XCTAssertEqual(viewModel.announcementViewModel?.title, "JITM Message")
129+
}
130+
131+
func prepareStoresToShowJustInTimeMessage(_ response: Result<Yosemite.JustInTimeMessage?, Error>) {
115132
stores.whenReceivingAction(ofType: ProductAction.self) { action in
116133
switch action {
117134
case let .checkProductsOnboardingEligibility(_, completion):
@@ -123,23 +140,15 @@ final class DashboardViewModelTests: XCTestCase {
123140
stores.whenReceivingAction(ofType: JustInTimeMessageAction.self) { action in
124141
switch action {
125142
case let .loadMessage(_, _, _, completion):
126-
completion(.success(Yosemite.JustInTimeMessage.fake().copy(title: "JITM Message")))
143+
completion(response)
127144
default:
128145
XCTFail("Received unsupported action: \(action)")
129146
}
130147
}
131-
let viewModel = DashboardViewModel(stores: stores)
132-
133-
// When
134-
viewModel.syncAnnouncements(for: sampleSiteID)
135-
136-
// Then
137-
XCTAssertEqual(viewModel.announcementViewModel?.title, "JITM Message")
138148
}
139149

140150
func test_no_announcement_to_display_when_no_announcements_are_synced() {
141151
// Given
142-
let stores = MockStoresManager(sessionManager: .makeForTesting())
143152
stores.whenReceivingAction(ofType: ProductAction.self) { action in
144153
switch action {
145154
case let .checkProductsOnboardingEligibility(_, completion):
@@ -192,4 +201,47 @@ final class DashboardViewModelTests: XCTestCase {
192201
// Then
193202
XCTAssertNil(viewModel.announcementViewModel)
194203
}
204+
205+
func test_fetch_success_analytics_logged_when_just_in_time_message_retrieved() {
206+
// Given
207+
let message = Yosemite.JustInTimeMessage.fake().copy(messageID: "test-message-id",
208+
featureClass: "test-feature-class")
209+
prepareStoresToShowJustInTimeMessage(.success(message))
210+
let viewModel = DashboardViewModel(stores: stores, analytics: analytics)
211+
212+
// When
213+
viewModel.syncAnnouncements(for: sampleSiteID)
214+
215+
// Then
216+
guard let eventIndex = analyticsProvider.receivedEvents.firstIndex(of: "jitm_fetch_success"),
217+
let properties = analyticsProvider.receivedProperties[eventIndex] as? [String: AnyHashable]
218+
else {
219+
return XCTFail("Expected event was not logged")
220+
}
221+
222+
assertEqual("my_store", properties["source"] as? String)
223+
assertEqual("test-message-id", properties["jitm"] as? String)
224+
assertEqual(1, properties["count"] as? Int64)
225+
}
226+
227+
func test_fetch_failure_analytics_logged_when_just_in_time_message_errors() {
228+
// Given
229+
let error = DotcomError.noRestRoute
230+
prepareStoresToShowJustInTimeMessage(.failure(error))
231+
let viewModel = DashboardViewModel(stores: stores, analytics: analytics)
232+
233+
// When
234+
viewModel.syncAnnouncements(for: sampleSiteID)
235+
236+
// Then
237+
guard let eventIndex = analyticsProvider.receivedEvents.firstIndex(of: "jitm_fetch_failure"),
238+
let properties = analyticsProvider.receivedProperties[eventIndex] as? [String: AnyHashable]
239+
else {
240+
return XCTFail("Expected event was not logged")
241+
}
242+
243+
assertEqual("my_store", properties["source"] as? String)
244+
assertEqual("Networking.DotcomError", properties["error_domain"] as? String)
245+
assertEqual("Dotcom Invalid REST Route", properties["error_description"] as? String)
246+
}
195247
}

0 commit comments

Comments
 (0)