Skip to content

Commit

Permalink
feat: in app click tracking (#284)
Browse files Browse the repository at this point in the history
  • Loading branch information
Shahroz16 committed Apr 19, 2023
1 parent cdcb788 commit 4ed8edb
Show file tree
Hide file tree
Showing 22 changed files with 83 additions and 66 deletions.
11 changes: 8 additions & 3 deletions Sources/Common/Background Queue/Queue.swift
Expand Up @@ -31,7 +31,7 @@ public protocol Queue: AutoMockable {
See list of refactors: https://github.com/customerio/issues/issues/6934
*/

func addTrackInAppDeliveryTask(deliveryId: String, event: InAppMetric) -> ModifyQueueResult
func addTrackInAppDeliveryTask(deliveryId: String, event: InAppMetric, metaData: [String: String]) -> ModifyQueueResult

/**
Add a task to the queue to be performed sometime in the future.
Expand All @@ -57,6 +57,10 @@ public protocol Queue: AutoMockable {
}

public extension Queue {
func addTrackInAppDeliveryTask(deliveryId: String, event: InAppMetric, metaData: [String: String] = [:]) -> ModifyQueueResult {
addTrackInAppDeliveryTask(deliveryId: deliveryId, event: event, metaData: metaData)
}

func addTask<TaskData: Codable>(
type: String,
// sourcery:Type=AnyEncodable
Expand Down Expand Up @@ -122,15 +126,16 @@ public class CioQueue: Queue {
self.dateUtil = dateUtil
}

public func addTrackInAppDeliveryTask(deliveryId: String, event: InAppMetric) -> ModifyQueueResult {
public func addTrackInAppDeliveryTask(deliveryId: String, event: InAppMetric, metaData: [String: String]) -> ModifyQueueResult {
addTask(
type: QueueTaskType.trackDeliveryMetric.rawValue,
data: TrackDeliveryEventRequestBody(
type: .inApp,
payload: DeliveryPayload(
deliveryId: deliveryId,
event: event,
timestamp: dateUtil.now
timestamp: dateUtil.now,
metaData: metaData
)
)
)
Expand Down
Expand Up @@ -14,11 +14,13 @@ internal struct DeliveryPayload: Codable {
internal let deliveryId: String
internal let event: InAppMetric
internal let timestamp: Date
internal let metaData: [String: String]

enum CodingKeys: String, CodingKey {
case deliveryId = "delivery_id"
case event
case timestamp
case metaData = "metadata"
}
}

Expand Down
@@ -1,4 +1,4 @@
// Generated using Sourcery 2.0.1 — https://github.com/krzysztofzablocki/Sourcery
// Generated using Sourcery 2.0.2 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
// swiftlint:disable all

Expand Down
2 changes: 1 addition & 1 deletion Sources/Common/autogenerated/AutoLenses.generated.swift
@@ -1,4 +1,4 @@
// Generated using Sourcery 2.0.1 — https://github.com/krzysztofzablocki/Sourcery
// Generated using Sourcery 2.0.2 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
// swiftlint:disable all

Expand Down
54 changes: 9 additions & 45 deletions Sources/Common/autogenerated/AutoMockable.generated.swift
@@ -1,4 +1,4 @@
// Generated using Sourcery 2.0.1 — https://github.com/krzysztofzablocki/Sourcery
// Generated using Sourcery 2.0.2 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
// swiftlint:disable all

Expand Down Expand Up @@ -1672,25 +1672,25 @@ public class QueueMock: Queue, Mock {
}

/// The arguments from the *last* time the function was called.
public private(set) var addTrackInAppDeliveryTaskReceivedArguments: (deliveryId: String, event: InAppMetric)?
public private(set) var addTrackInAppDeliveryTaskReceivedArguments: (deliveryId: String, event: InAppMetric, metaData: [String: String])?
/// Arguments from *all* of the times that the function was called.
public private(set) var addTrackInAppDeliveryTaskReceivedInvocations: [(deliveryId: String, event: InAppMetric)] = []
public private(set) var addTrackInAppDeliveryTaskReceivedInvocations: [(deliveryId: String, event: InAppMetric, metaData: [String: String])] = []
/// Value to return from the mocked function.
public var addTrackInAppDeliveryTaskReturnValue: ModifyQueueResult!
/**
Set closure to get called when function gets called. Great way to test logic or return a value for the function.
The closure has first priority to return a value for the mocked function. If the closure returns `nil`,
then the mock will attempt to return the value for `addTrackInAppDeliveryTaskReturnValue`
*/
public var addTrackInAppDeliveryTaskClosure: ((String, InAppMetric) -> ModifyQueueResult)?
public var addTrackInAppDeliveryTaskClosure: ((String, InAppMetric, [String: String]) -> ModifyQueueResult)?

/// Mocked function for `addTrackInAppDeliveryTask(deliveryId: String, event: InAppMetric)`. Your opportunity to return a mocked value and check result of mock in test code.
public func addTrackInAppDeliveryTask(deliveryId: String, event: InAppMetric) -> ModifyQueueResult {
/// Mocked function for `addTrackInAppDeliveryTask(deliveryId: String, event: InAppMetric, metaData: [String: String])`. Your opportunity to return a mocked value and check result of mock in test code.
public func addTrackInAppDeliveryTask(deliveryId: String, event: InAppMetric, metaData: [String: String]) -> ModifyQueueResult {
mockCalled = true
addTrackInAppDeliveryTaskCallsCount += 1
addTrackInAppDeliveryTaskReceivedArguments = (deliveryId: deliveryId, event: event)
addTrackInAppDeliveryTaskReceivedInvocations.append((deliveryId: deliveryId, event: event))
return addTrackInAppDeliveryTaskClosure.map { $0(deliveryId, event) } ?? addTrackInAppDeliveryTaskReturnValue
addTrackInAppDeliveryTaskReceivedArguments = (deliveryId: deliveryId, event: event, metaData: metaData)
addTrackInAppDeliveryTaskReceivedInvocations.append((deliveryId: deliveryId, event: event, metaData: metaData))
return addTrackInAppDeliveryTaskClosure.map { $0(deliveryId, event, metaData) } ?? addTrackInAppDeliveryTaskReturnValue
}

// MARK: - addTask<TaskData: Codable>
Expand Down Expand Up @@ -2131,11 +2131,6 @@ public class QueueStorageMock: QueueStorage, Mock {
deleteReceivedArguments = nil
deleteReceivedInvocations = []

mockCalled = false // do last as resetting properties above can make this true
deleteTasksMemberOfGroupCallsCount = 0
deleteTasksMemberOfGroupReceivedArguments = nil
deleteTasksMemberOfGroupReceivedInvocations = []

mockCalled = false // do last as resetting properties above can make this true
deleteExpiredCallsCount = 0

Expand Down Expand Up @@ -2322,37 +2317,6 @@ public class QueueStorageMock: QueueStorage, Mock {
return deleteClosure.map { $0(storageId) } ?? deleteReturnValue
}

// MARK: - deleteTasksMemberOfGroup

/// Number of times the function was called.
public private(set) var deleteTasksMemberOfGroupCallsCount = 0
/// `true` if the function was ever called.
public var deleteTasksMemberOfGroupCalled: Bool {
deleteTasksMemberOfGroupCallsCount > 0
}

/// The arguments from the *last* time the function was called.
public private(set) var deleteTasksMemberOfGroupReceivedArguments: String?
/// Arguments from *all* of the times that the function was called.
public private(set) var deleteTasksMemberOfGroupReceivedInvocations: [String] = []
/// Value to return from the mocked function.
public var deleteTasksMemberOfGroupReturnValue: [QueueTaskMetadata]!
/**
Set closure to get called when function gets called. Great way to test logic or return a value for the function.
The closure has first priority to return a value for the mocked function. If the closure returns `nil`,
then the mock will attempt to return the value for `deleteTasksMemberOfGroupReturnValue`
*/
public var deleteTasksMemberOfGroupClosure: ((String) -> [QueueTaskMetadata])?

/// Mocked function for `deleteTasksMemberOfGroup(groupId: String)`. Your opportunity to return a mocked value and check result of mock in test code.
public func deleteTasksMemberOfGroup(groupId: String) -> [QueueTaskMetadata] {
mockCalled = true
deleteTasksMemberOfGroupCallsCount += 1
deleteTasksMemberOfGroupReceivedArguments = groupId
deleteTasksMemberOfGroupReceivedInvocations.append(groupId)
return deleteTasksMemberOfGroupClosure.map { $0(groupId) } ?? deleteTasksMemberOfGroupReturnValue
}

// MARK: - deleteExpired

/// Number of times the function was called.
Expand Down
2 changes: 1 addition & 1 deletion Sources/MessagingInApp/MessagingInAppImplementation.swift
Expand Up @@ -102,7 +102,7 @@ extension MessagingInAppImplementation: GistDelegate {
if action != "gist://close" {
if let deliveryId = getDeliveryId(from: message) {
// the state of the SDK does not change if adding this queue task isn't successful so ignore result
_ = queue.addTrackInAppDeliveryTask(deliveryId: deliveryId, event: .clicked)
_ = queue.addTrackInAppDeliveryTask(deliveryId: deliveryId, event: .clicked, metaData: ["action_name": name, "action_value": action])
}
}

Expand Down
@@ -1,4 +1,4 @@
// Generated using Sourcery 2.0.1 — https://github.com/krzysztofzablocki/Sourcery
// Generated using Sourcery 2.0.2 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
// swiftlint:disable all

Expand Down
@@ -1,4 +1,4 @@
// Generated using Sourcery 2.0.1 — https://github.com/krzysztofzablocki/Sourcery
// Generated using Sourcery 2.0.2 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
// swiftlint:disable all

Expand Down
@@ -1,4 +1,4 @@
// Generated using Sourcery 2.0.1 — https://github.com/krzysztofzablocki/Sourcery
// Generated using Sourcery 2.0.2 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
// swiftlint:disable all

Expand Down
@@ -1,4 +1,4 @@
// Generated using Sourcery 2.0.1 — https://github.com/krzysztofzablocki/Sourcery
// Generated using Sourcery 2.0.2 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
// swiftlint:disable all

Expand Down
@@ -1,4 +1,4 @@
// Generated using Sourcery 2.0.1 — https://github.com/krzysztofzablocki/Sourcery
// Generated using Sourcery 2.0.2 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
// swiftlint:disable all

Expand Down
@@ -1,4 +1,4 @@
// Generated using Sourcery 2.0.1 — https://github.com/krzysztofzablocki/Sourcery
// Generated using Sourcery 2.0.2 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
// swiftlint:disable all

Expand Down
@@ -1,4 +1,4 @@
// Generated using Sourcery 2.0.1 — https://github.com/krzysztofzablocki/Sourcery
// Generated using Sourcery 2.0.2 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
// swiftlint:disable all

Expand Down
@@ -1,4 +1,4 @@
// Generated using Sourcery 2.0.1 — https://github.com/krzysztofzablocki/Sourcery
// Generated using Sourcery 2.0.2 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
// swiftlint:disable all

Expand Down
@@ -1,4 +1,4 @@
// Generated using Sourcery 2.0.1 — https://github.com/krzysztofzablocki/Sourcery
// Generated using Sourcery 2.0.2 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
// swiftlint:disable all

Expand Down
@@ -1,4 +1,4 @@
// Generated using Sourcery 2.0.1 — https://github.com/krzysztofzablocki/Sourcery
// Generated using Sourcery 2.0.2 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
// swiftlint:disable all

Expand Down
@@ -1,4 +1,4 @@
// Generated using Sourcery 2.0.1 — https://github.com/krzysztofzablocki/Sourcery
// Generated using Sourcery 2.0.2 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
// swiftlint:disable all

Expand Down
@@ -1,4 +1,4 @@
// Generated using Sourcery 2.0.1 — https://github.com/krzysztofzablocki/Sourcery
// Generated using Sourcery 2.0.2 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
// swiftlint:disable all

Expand Down
@@ -1,4 +1,4 @@
// Generated using Sourcery 2.0.1 — https://github.com/krzysztofzablocki/Sourcery
// Generated using Sourcery 2.0.2 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
// swiftlint:disable all

Expand Down
2 changes: 1 addition & 1 deletion Sources/Tracking/autogenerated/AutoLenses.generated.swift
@@ -1,4 +1,4 @@
// Generated using Sourcery 2.0.1 — https://github.com/krzysztofzablocki/Sourcery
// Generated using Sourcery 2.0.2 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
// swiftlint:disable all

Expand Down
@@ -1,4 +1,4 @@
// Generated using Sourcery 2.0.1 — https://github.com/krzysztofzablocki/Sourcery
// Generated using Sourcery 2.0.2 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
// swiftlint:disable all

Expand Down
46 changes: 46 additions & 0 deletions Tests/MessagingInApp/MessagingInAppImplementationTest.swift
Expand Up @@ -12,12 +12,14 @@ class MessagingInAppImplementationTest: UnitTest {
private let inAppProviderMock = InAppProviderMock()
private let eventListenerMock = InAppEventListenerMock()
private let profileStoreMock = ProfileStoreMock()
private let backgroundQueueMock = QueueMock()

override func setUp() {
super.setUp()

diGraph.override(value: inAppProviderMock, forType: InAppProvider.self)
diGraph.override(value: profileStoreMock, forType: ProfileStore.self)
diGraph.override(value: backgroundQueueMock, forType: Queue.self)

messagingInApp = MessagingInAppImplementation(diGraph: diGraph)
messagingInApp.initialize(eventListener: eventListenerMock)
Expand Down Expand Up @@ -101,6 +103,11 @@ class MessagingInAppImplementationTest: UnitTest {
let givenGistMessage = Message.random
let expectedInAppMessage = InAppMessage(gistMessage: givenGistMessage)

backgroundQueueMock.addTrackInAppDeliveryTaskReturnValue = (
success: true,
queueStatus: QueueStatus.successAddingSingleTask
)

// Message opened
XCTAssertFalse(eventListenerMock.messageShownCalled)
messagingInApp.messageShown(message: givenGistMessage)
Expand Down Expand Up @@ -139,6 +146,11 @@ class MessagingInAppImplementationTest: UnitTest {
func test_eventListeners_expectCallListenerForEachEvent() {
let givenGistMessage = Message.random

backgroundQueueMock.addTrackInAppDeliveryTaskReturnValue = (
success: true,
queueStatus: QueueStatus.successAddingSingleTask
)

// Message opened
XCTAssertEqual(eventListenerMock.messageShownCallsCount, 0)
messagingInApp.messageShown(message: givenGistMessage)
Expand Down Expand Up @@ -175,6 +187,11 @@ class MessagingInAppImplementationTest: UnitTest {
let givenAction = "gist://close"
let givenName = String.random

backgroundQueueMock.addTrackInAppDeliveryTaskReturnValue = (
success: true,
queueStatus: QueueStatus.successAddingSingleTask
)

XCTAssertEqual(eventListenerMock.messageActionTakenCallsCount, 0)

messagingInApp.action(
Expand All @@ -183,9 +200,38 @@ class MessagingInAppImplementationTest: UnitTest {
action: givenAction,
name: givenName
)

XCTAssertEqual(eventListenerMock.messageActionTakenCallsCount, 1)
XCTAssertEqual(eventListenerMock.messageActionTakenReceivedArguments?.message, expectedInAppMessage)
XCTAssertEqual(eventListenerMock.messageActionTakenReceivedArguments?.actionValue, givenAction)
XCTAssertEqual(eventListenerMock.messageActionTakenReceivedArguments?.actionName, givenName)

// make sure there is no click tracking for "close" action
XCTAssertEqual(backgroundQueueMock.addTrackInAppDeliveryTaskCallsCount, 0)
}

func test_inAppTracking_givenCustomAction_expectBQTrackInAppClicked() {
let givenGistMessage = Message.random
let expectedInAppMessage = InAppMessage(gistMessage: givenGistMessage)
let givenCurrentRoute = String.random
let givenAction = String.random
let givenName = String.random
let givenMetaData = ["action_name": givenName, "action_value": givenAction]

backgroundQueueMock.addTrackInAppDeliveryTaskReturnValue = (
success: true,
queueStatus: QueueStatus.successAddingSingleTask
)

messagingInApp.action(
message: givenGistMessage,
currentRoute: givenCurrentRoute,
action: givenAction,
name: givenName
)

XCTAssertEqual(backgroundQueueMock.addTrackInAppDeliveryTaskReceivedArguments?.deliveryId, expectedInAppMessage.deliveryId)
XCTAssertEqual(backgroundQueueMock.addTrackInAppDeliveryTaskReceivedArguments?.event, .clicked)
XCTAssertEqual(backgroundQueueMock.addTrackInAppDeliveryTaskReceivedArguments?.metaData, givenMetaData)
}
}

0 comments on commit 4ed8edb

Please sign in to comment.