Skip to content

Commit 4933fd7

Browse files
committed
Merge branch 'trunk' into backlog/WOOMOB-869-remove-pos-tab-i2-feature-flag-with-refactoring
# Conflicts: # WooCommerce/WooCommerce.xcodeproj/project.pbxproj
2 parents c144a6b + 2c9fd8a commit 4933fd7

32 files changed

+1237
-303
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import Foundation
2+
3+
/// Tracks the waiting time for a given scenario, allowing to evaluate as analytics
4+
/// how much time in seconds it took between the init and `end` function call
5+
///
6+
public class WaitingTimeTracker {
7+
private let trackScenario: WooAnalyticsEvent.WaitingTime.Scenario
8+
private let currentTimestampSeconds: () -> TimeInterval
9+
private let waitingStartedTimestamp: TimeInterval
10+
11+
public enum TrackingUnit {
12+
case seconds
13+
case milliseconds
14+
}
15+
16+
public init(trackScenario: WooAnalyticsEvent.WaitingTime.Scenario,
17+
currentTimestampSeconds: @escaping () -> TimeInterval = { Date().timeIntervalSince1970 }
18+
) {
19+
self.trackScenario = trackScenario
20+
self.currentTimestampSeconds = currentTimestampSeconds
21+
waitingStartedTimestamp = currentTimestampSeconds()
22+
}
23+
24+
/// Default `end()` method to preserve interface compatibility. By default, tracks in `.seconds`
25+
/// - Returns: The analytics event to be tracked.
26+
///
27+
public func end() -> WooAnalyticsEvent {
28+
end(using: .seconds)
29+
}
30+
31+
/// End the waiting time by evaluating the elapsed time from the init,
32+
/// and returning an analytics event for tracking.
33+
///
34+
/// - Parameter trackingUnit: Defines whether the elapsed time should be tracked in `.seconds` or `.milliseconds` (default is `.seconds`).
35+
/// - Returns: The analytics event to be tracked.
36+
///
37+
public func end(using trackingUnit: TrackingUnit = .seconds) -> WooAnalyticsEvent {
38+
let elapsedTime = calculateElapsedTime(in: trackingUnit)
39+
return .WaitingTime.waitingFinished(scenario: trackScenario, elapsedTime: elapsedTime)
40+
}
41+
42+
/// Calculates elapsed time in the specified tracking unit.
43+
///
44+
private func calculateElapsedTime(in trackingUnit: TrackingUnit) -> TimeInterval {
45+
let elapsedTime = currentTimestampSeconds() - waitingStartedTimestamp
46+
return trackingUnit == .milliseconds ? elapsedTime * 1000 : elapsedTime
47+
}
48+
}
49+
50+
// MARK: - Waiting Time measurement
51+
//
52+
public extension WooAnalyticsEvent {
53+
enum WaitingTime {
54+
/// Possible Waiting time scenarios
55+
public enum Scenario {
56+
case orderDetails
57+
case dashboardTopPerformers
58+
case dashboardMainStats
59+
case analyticsHub
60+
case appStartup
61+
case pointOfSaleLoaded
62+
}
63+
64+
private enum Keys {
65+
static let waitingTime = "waiting_time"
66+
static let millisecondsTimeElapsedInSplashScreen = "milliseconds_time_elapsed_in_splash_screen"
67+
}
68+
69+
static func waitingFinished(scenario: Scenario, elapsedTime: TimeInterval) -> WooAnalyticsEvent {
70+
switch scenario {
71+
case .orderDetails:
72+
return WooAnalyticsEvent(statName: .orderDetailWaitingTimeLoaded, properties: [Keys.waitingTime: elapsedTime])
73+
case .dashboardTopPerformers:
74+
return WooAnalyticsEvent(statName: .dashboardTopPerformersWaitingTimeLoaded, properties: [Keys.waitingTime: elapsedTime])
75+
case .dashboardMainStats:
76+
return WooAnalyticsEvent(statName: .dashboardMainStatsWaitingTimeLoaded, properties: [Keys.waitingTime: elapsedTime])
77+
case .analyticsHub:
78+
return WooAnalyticsEvent(statName: .analyticsHubWaitingTimeLoaded, properties: [Keys.waitingTime: elapsedTime])
79+
case .appStartup:
80+
return WooAnalyticsEvent(statName: .applicationOpenedWaitingTimeLoaded, properties: [Keys.waitingTime: elapsedTime])
81+
case .pointOfSaleLoaded:
82+
return WooAnalyticsEvent(statName: .pointOfSaleLoaded, properties: [Keys.millisecondsTimeElapsedInSplashScreen: elapsedTime])
83+
}
84+
}
85+
}
86+
}

Modules/Sources/Yosemite/Tools/POS/POSCatalogSettingsService.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// periphery:ignore:all
21
import Foundation
32
import GRDB
43
import protocol Storage.GRDBManagerProtocol
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import XCTest
2+
@testable import WooFoundation
3+
4+
/// WaitingTimeTracker Unit Tests
5+
///
6+
final class WaitingTimeTrackerTests: XCTestCase {
7+
func testTimeElapsedEvaluationIsCorrect() {
8+
var currentTimeCallCounter = 0.0
9+
10+
// Given
11+
let waitingTracker = WaitingTimeTracker(trackScenario: .orderDetails) {
12+
currentTimeCallCounter += 1
13+
return currentTimeCallCounter * 10
14+
}
15+
16+
// When
17+
let event = waitingTracker.end()
18+
19+
// Then
20+
XCTAssertEqual(event.properties["waiting_time"] as? TimeInterval, 10.0)
21+
}
22+
23+
func testOrderDetailsTrackScenarioTriggersExpectedAnalyticsStat() {
24+
// Given
25+
let waitingTracker = WaitingTimeTracker(trackScenario: .orderDetails, currentTimestampSeconds: { 0 })
26+
27+
// When
28+
let event = waitingTracker.end()
29+
30+
// Then
31+
XCTAssertEqual(event.statName.rawValue, WooAnalyticsStat.orderDetailWaitingTimeLoaded.rawValue)
32+
}
33+
34+
func testTopPerformersTrackScenarioTriggersExpectedAnalyticsStat() {
35+
// Given
36+
let waitingTracker = WaitingTimeTracker(trackScenario: .dashboardTopPerformers,
37+
currentTimestampSeconds: { 0 }
38+
)
39+
40+
// When
41+
let event = waitingTracker.end()
42+
43+
// Then
44+
XCTAssertEqual(event.statName.rawValue, WooAnalyticsStat.dashboardTopPerformersWaitingTimeLoaded.rawValue)
45+
}
46+
47+
func testMainStatsTrackScenarioTriggersExpectedAnalyticsStat() {
48+
// Given
49+
let waitingTracker = WaitingTimeTracker(trackScenario: .dashboardMainStats,
50+
currentTimestampSeconds: { 0 }
51+
)
52+
53+
// When
54+
let event = waitingTracker.end()
55+
56+
// Then
57+
XCTAssertEqual(event.statName.rawValue, WooAnalyticsStat.dashboardMainStatsWaitingTimeLoaded.rawValue)
58+
}
59+
60+
func test_analytics_hub_track_scenario_triggers_expected_analytics_stat() {
61+
// Given
62+
let waitingTracker = WaitingTimeTracker(trackScenario: .analyticsHub,
63+
currentTimestampSeconds: { 0 }
64+
)
65+
66+
// When
67+
let event = waitingTracker.end()
68+
69+
// Then
70+
XCTAssertEqual(event.statName.rawValue, WooAnalyticsStat.analyticsHubWaitingTimeLoaded.rawValue)
71+
}
72+
73+
func test_appStartup_track_scenario_triggers_expected_analytics_stat() {
74+
// Given
75+
let waitingTracker = WaitingTimeTracker(trackScenario: .appStartup,
76+
currentTimestampSeconds: { 0 }
77+
)
78+
79+
// When
80+
let event = waitingTracker.end()
81+
82+
// Then
83+
XCTAssertEqual(event.statName.rawValue, WooAnalyticsStat.applicationOpenedWaitingTimeLoaded.rawValue)
84+
}
85+
86+
func test_timeElapsed_evaluation_in_milliseconds_is_correct() {
87+
// Given
88+
var currentTimeCallCounter = 0.0
89+
let expectedReceivedWaitingTime = 10_000.0 // 10s * 1000 ms
90+
let waitingTracker = WaitingTimeTracker(trackScenario: .orderDetails) {
91+
currentTimeCallCounter += 1
92+
return currentTimeCallCounter * 10
93+
}
94+
95+
// When
96+
let event = waitingTracker.end(using: .milliseconds)
97+
98+
// Then
99+
XCTAssertEqual(event.properties["waiting_time"] as? TimeInterval, expectedReceivedWaitingTime)
100+
}
101+
102+
func test_track_scenario_triggers_expected_analytics_stat_in_milliseconds() {
103+
// Given
104+
let waitingTracker = WaitingTimeTracker(trackScenario: .pointOfSaleLoaded,
105+
currentTimestampSeconds: { 0 })
106+
107+
// When
108+
let event = waitingTracker.end(using: .milliseconds)
109+
110+
// Then
111+
XCTAssertEqual(event.statName.rawValue, WooAnalyticsStat.pointOfSaleLoaded.rawValue)
112+
}
113+
}

WooCommerce/Classes/Analytics/AppStartupWaitingTimeTracker.swift

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import Foundation
22
import Yosemite
3+
import class WooFoundation.WaitingTimeTracker
34
import protocol WooFoundation.Analytics
45

56
/// Tracks the waiting time for app startup, allowing to evaluate as analytics
67
/// how much time in seconds it took between the init and the final `end(action:)` function call.
78
///
8-
final class AppStartupWaitingTimeTracker: WaitingTimeTracker {
9+
final class AppStartupWaitingTimeTracker {
910

1011
/// All actions tracked in the app startup waiting time.
1112
///
@@ -19,10 +20,13 @@ final class AppStartupWaitingTimeTracker: WaitingTimeTracker {
1920
/// Represents all of the app startup actions waiting to be completed.
2021
///
2122
private(set) var startupActionsPending = StartupAction.allCases
23+
private let analyticsService: Analytics
24+
private let waitingTimeTracker: WaitingTimeTracker
2225

2326
init(analyticsService: Analytics = ServiceLocator.analytics,
2427
currentTimestampSeconds: @escaping () -> TimeInterval = { Date().timeIntervalSince1970 }) {
25-
super.init(trackScenario: .appStartup, analyticsService: analyticsService, currentTimestampSeconds: currentTimestampSeconds)
28+
self.analyticsService = analyticsService
29+
self.waitingTimeTracker = WaitingTimeTracker(trackScenario: .appStartup, currentTimestampSeconds: currentTimestampSeconds)
2630
}
2731

2832
/// Ends the waiting time for the provided startup action.
@@ -39,7 +43,7 @@ final class AppStartupWaitingTimeTracker: WaitingTimeTracker {
3943

4044
// If all actions completed without any errors, send the analytics event.
4145
if startupActionsPending.isEmpty {
42-
super.end()
46+
analyticsService.track(event: waitingTimeTracker.end())
4347
}
4448
}
4549

@@ -48,7 +52,7 @@ final class AppStartupWaitingTimeTracker: WaitingTimeTracker {
4852
/// This can be used to stop tracking in scenarios that would skew the waiting time analysis.
4953
/// For example, when the app is backgrounded or a startup action has an API error or network connection error.
5054
///
51-
override func end() {
55+
func endWithoutTracking() {
5256
startupActionsPending.removeAll()
5357
}
5458
}

WooCommerce/Classes/Analytics/WaitingTimeTracker.swift

Lines changed: 0 additions & 52 deletions
This file was deleted.

WooCommerce/Classes/Analytics/WooAnalyticsEvent+WooApp.swift

Lines changed: 0 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2565,45 +2565,6 @@ extension WooAnalyticsEvent {
25652565
}
25662566
}
25672567

2568-
2569-
// MARK: - Waiting Time measurement
2570-
//
2571-
extension WooAnalyticsEvent {
2572-
enum WaitingTime {
2573-
/// Possible Waiting time scenarios
2574-
enum Scenario {
2575-
case orderDetails
2576-
case dashboardTopPerformers
2577-
case dashboardMainStats
2578-
case analyticsHub
2579-
case appStartup
2580-
case pointOfSaleLoaded
2581-
}
2582-
2583-
private enum Keys {
2584-
static let waitingTime = "waiting_time"
2585-
static let millisecondsTimeElapsedInSplashScreen = "milliseconds_time_elapsed_in_splash_screen"
2586-
}
2587-
2588-
static func waitingFinished(scenario: Scenario, elapsedTime: TimeInterval) -> WooAnalyticsEvent {
2589-
switch scenario {
2590-
case .orderDetails:
2591-
return WooAnalyticsEvent(statName: .orderDetailWaitingTimeLoaded, properties: [Keys.waitingTime: elapsedTime])
2592-
case .dashboardTopPerformers:
2593-
return WooAnalyticsEvent(statName: .dashboardTopPerformersWaitingTimeLoaded, properties: [Keys.waitingTime: elapsedTime])
2594-
case .dashboardMainStats:
2595-
return WooAnalyticsEvent(statName: .dashboardMainStatsWaitingTimeLoaded, properties: [Keys.waitingTime: elapsedTime])
2596-
case .analyticsHub:
2597-
return WooAnalyticsEvent(statName: .analyticsHubWaitingTimeLoaded, properties: [Keys.waitingTime: elapsedTime])
2598-
case .appStartup:
2599-
return WooAnalyticsEvent(statName: .applicationOpenedWaitingTimeLoaded, properties: [Keys.waitingTime: elapsedTime])
2600-
case .pointOfSaleLoaded:
2601-
return WooAnalyticsEvent(statName: .pointOfSaleLoaded, properties: [Keys.millisecondsTimeElapsedInSplashScreen: elapsedTime])
2602-
}
2603-
}
2604-
}
2605-
}
2606-
26072568
// MARK: - Site picker
26082569
//
26092570
extension WooAnalyticsEvent {

WooCommerce/Classes/AppDelegate.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ private extension AppDelegate {
436436
/// Cancel the app startup waiting time tracker
437437
///
438438
func cancelStartupWaitingTimeTracker() {
439-
ServiceLocator.startupWaitingTimeTracker.end()
439+
ServiceLocator.startupWaitingTimeTracker.endWithoutTracking()
440440
}
441441

442442
func handleLaunchArguments() {
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import SwiftUI
2+
3+
struct BookingListView: View {
4+
// periphery:ignore
5+
@ObservedObject private var viewModel: BookingListViewModel
6+
7+
init(viewModel: BookingListViewModel) {
8+
self.viewModel = viewModel
9+
}
10+
11+
var body: some View {
12+
Text("Hello, World!")
13+
}
14+
}

0 commit comments

Comments
 (0)