Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: allow set person properties after identify #249

Merged
merged 10 commits into from
Nov 13, 2024
Merged
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## Next

- fix: allow changing person properties after identify ([#249](https://github.com/PostHog/posthog-ios/pull/249))

## 3.15.1 - 2024-11-12

- fix: accessing UI APIs off main thread to get screen size ([#247](https://github.com/PostHog/posthog-ios/pull/247))
Expand Down
14 changes: 13 additions & 1 deletion PostHog/PostHogSDK.swift
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,9 @@ let maxRetryDelay = 30.0

let isIdentified = storageManager.isIdentified()

if distinctId != oldDistinctId, !isIdentified {
let hasDifferentDistinctId = distinctId != oldDistinctId

if hasDifferentDistinctId, !isIdentified {
// We keep the AnonymousId to be used by decide calls and identify to link the previousId
storageManager.setAnonymousId(oldDistinctId)
storageManager.setDistinctId(distinctId)
Expand All @@ -490,6 +492,16 @@ let maxRetryDelay = 30.0
if shouldReloadFlagsForTesting {
reloadFeatureFlags()
}
// we need to make sure the user props update is for the same user
// otherwise they have to reset and identify again
} else if !hasDifferentDistinctId, !(userProperties?.isEmpty ?? true) || !(userPropertiesSetOnce?.isEmpty ?? true) {
capture("$set",
distinctId: distinctId,
userProperties: userProperties,
userPropertiesSetOnce: userPropertiesSetOnce)
ioannisj marked this conversation as resolved.
Show resolved Hide resolved
marandaneto marked this conversation as resolved.
Show resolved Hide resolved

// Note we don't reload flags on property changes as these get processed async

} else {
hedgeLog("already identified with id: \(oldDistinctId)")
}
Expand Down
99 changes: 90 additions & 9 deletions PostHogTests/PostHogSDKTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,43 @@ class PostHogSDKTest: QuickSpec {
}

it("does not capture identify event if already identified") {
let sut = self.getSut()
let sut = self.getSut(
flushAt: 2
)

sut.identify("distinctId",
userProperties: ["userProp": "value"],
userPropertiesSetOnce: ["userPropOnce": "value"])

sut.identify("distinctId")
sut.capture("satisfy_queue")

let events = getBatchedEvents(server)

expect(events.count) == 2

expect(events[0].event) == "$identify"
expect(events[1].event) == "satisfy_queue"

expect(events[0].distinctId) == "distinctId"
let anonId = sut.getAnonymousId()
expect(events[0].properties["$anon_distinct_id"] as? String) == anonId
expect(events[0].properties["$is_identified"] as? Bool) == true

let set = events[0].properties["$set"] as? [String: Any] ?? [:]
expect(set["userProp"] as? String) == "value"

let setOnce = events[0].properties["$set_once"] as? [String: Any] ?? [:]
expect(setOnce["userPropOnce"] as? String) == "value"

sut.reset()
sut.close()
}

it("updates user props if already identified but user properties are set") {
let sut = self.getSut(
flushAt: 2
)

sut.identify("distinctId",
userProperties: ["userProp": "value"],
Expand All @@ -168,20 +204,65 @@ class PostHogSDKTest: QuickSpec {

let events = getBatchedEvents(server)

expect(events.count) == 1
expect(events.count) == 2

let event = events.first!
expect(event.event) == "$identify"
expect(events[0].event) == "$identify"
expect(events[1].event) == "$set"

expect(events[0].distinctId) == "distinctId"
expect(events[1].distinctId) == events[0].distinctId

expect(event.distinctId) == "distinctId"
let anonId = sut.getAnonymousId()
expect(event.properties["$anon_distinct_id"] as? String) == anonId
expect(event.properties["$is_identified"] as? Bool) == true
expect(events[0].properties["$anon_distinct_id"] as? String) == anonId
expect(events[0].properties["$is_identified"] as? Bool) == true

let set = event.properties["$set"] as? [String: Any] ?? [:]
let set0 = events[0].properties["$set"] as? [String: Any] ?? [:]
expect(set0["userProp"] as? String) == "value"

let set1 = events[1].properties["$set"] as? [String: Any] ?? [:]
expect(set1["userProp2"] as? String) == "value2"

let setOnce0 = events[0].properties["$set_once"] as? [String: Any] ?? [:]
expect(setOnce0["userPropOnce"] as? String) == "value"

let setOnce1 = events[1].properties["$set_once"] as? [String: Any] ?? [:]
expect(setOnce1["userPropOnce2"] as? String) == "value2"

sut.reset()
sut.close()
}

it("does not capture user props for another distinctId even if user properties are set") {
let sut = self.getSut(
flushAt: 2
)

sut.identify("distinctId",
userProperties: ["userProp": "value"],
userPropertiesSetOnce: ["userPropOnce": "value"])

sut.identify("distinctId2",
userProperties: ["userProp2": "value2"],
userPropertiesSetOnce: ["userPropOnce2": "value2"])

sut.capture("satisfy_queue")

let events = getBatchedEvents(server)

expect(events.count) == 2

expect(events[0].event) == "$identify"
expect(events[1].event) == "satisfy_queue"

expect(events[0].distinctId) == "distinctId"
let anonId = sut.getAnonymousId()
expect(events[0].properties["$anon_distinct_id"] as? String) == anonId
expect(events[0].properties["$is_identified"] as? Bool) == true

let set = events[0].properties["$set"] as? [String: Any] ?? [:]
expect(set["userProp"] as? String) == "value"

let setOnce = event.properties["$set_once"] as? [String: Any] ?? [:]
let setOnce = events[0].properties["$set_once"] as? [String: Any] ?? [:]
expect(setOnce["userPropOnce"] as? String) == "value"

sut.reset()
Expand Down
Loading