diff --git a/iOS_SDK/OneSignalSDK/OneSignalCoreMocks/Extensions/NSDictionary+UnitTests.swift b/iOS_SDK/OneSignalSDK/OneSignalCoreMocks/Extensions/NSDictionary+UnitTests.swift index 4549dec3c..a8cea9cf0 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalCoreMocks/Extensions/NSDictionary+UnitTests.swift +++ b/iOS_SDK/OneSignalSDK/OneSignalCoreMocks/Extensions/NSDictionary+UnitTests.swift @@ -66,9 +66,15 @@ extension NSDictionary { } private func equals(_ x: Any, _ y: Any) -> Bool { - guard x is AnyHashable else { return false } - guard y is AnyHashable else { return false } - return (x as! AnyHashable) == (y as! AnyHashable) + switch (x, y) { + case let (x as NSNumber, y as NSNumber): + // Handle float equality imprecision + return abs(x.floatValue - y.floatValue) <= .ulpOfOne + default: + guard x is AnyHashable else { return false } + guard y is AnyHashable else { return false } + return (x as! AnyHashable) == (y as! AnyHashable) + } } /** diff --git a/iOS_SDK/OneSignalSDK/OneSignalUserTests/OneSignalUserTests.swift b/iOS_SDK/OneSignalSDK/OneSignalUserTests/OneSignalUserTests.swift index e0dc80c9c..6ac2e80e5 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalUserTests/OneSignalUserTests.swift +++ b/iOS_SDK/OneSignalSDK/OneSignalUserTests/OneSignalUserTests.swift @@ -137,4 +137,85 @@ final class OneSignalUserTests: XCTestCase { identityModel.clearData() } } + + /** + Tests multiple user updates should be combined and sent together. + Multiple session times should be added. + Adding and removing multiple tags should be combined correctly. + Language uses the last language that is set. + Location uses the last point that is set. + */ + func testBasicCombiningUserUpdateDeltas_resultsInOneRequest() throws { + /* Setup */ + + let client = MockOneSignalClient() + MockUserRequests.setDefaultCreateAnonUserResponses(with: client) + OneSignalCoreImpl.setSharedClient(client) + + /* When */ + + OneSignalUserManagerImpl.sharedInstance.sendSessionTime(100) + + // This adds a `session_count` property with value of 1 + // It also sets `refresh_device_metadata` to `true` + OneSignalUserManagerImpl.sharedInstance.startNewSession() + + OneSignalUserManagerImpl.sharedInstance.setLanguage("lang_1") + + OneSignalUserManagerImpl.sharedInstance.addTag(key: "tag_1", value: "value_1") + + OneSignalUserManagerImpl.sharedInstance.setLanguage("lang_2") + + OneSignalUserManagerImpl.sharedInstance.addTag(key: "tag_2", value: "value_2") + + OneSignalUserManagerImpl.sharedInstance.sendSessionTime(50) + + OneSignalUserManagerImpl.sharedInstance.setLocation(latitude: 123.123, longitude: 145.145) + + OneSignalUserManagerImpl.sharedInstance.removeTag("tag_1") + + OneSignalUserManagerImpl.sharedInstance.addTags(["a": "a", "b": "b", "c": "c"]) + + OneSignalUserManagerImpl.sharedInstance.startNewSession() + + let purchases = [ + ["sku": "sku1", "amount": "1.25", "iso": "USD"], + ["sku": "sku2", "amount": "3.99", "iso": "USD"] + ] + + OneSignalUserManagerImpl.sharedInstance.sendPurchases(purchases as [[String: AnyObject]]) + + OneSignalUserManagerImpl.sharedInstance.setLocation(latitude: 111.111, longitude: 222.222) + + /* Then */ + + OneSignalCoreMocks.waitForBackgroundThreads(seconds: 0.5) + + let expectedPayload: [String: Any] = [ + "deltas": [ + "session_time": 150, // addition of 2 session times + "session_count": 2, // addition of 2 session counts + "purchases": purchases + ], + "properties": [ + "lat": 111.111, + "long": 222.222, + "language": "lang_2", + "tags": [ + "tag_1": "", + "tag_2": "value_2", + "a": "a", + "b": "b", + "c": "c" + ] + ], + "refresh_device_metadata": true + ] + + // Assert there is an update user request with the expected payload + XCTAssertTrue(client.onlyOneRequest( + contains: "apps/test-app-id/users/by/onesignal_id/\(anonUserOSID)", + contains: expectedPayload) + ) + } }