From 59a075e9128684c91dfffa3b57914f4c39a67dac Mon Sep 17 00:00:00 2001 From: Prateek Srivastava Date: Thu, 17 Sep 2015 16:08:38 -0700 Subject: [PATCH] Support not setting traits on Mixpanel --- .../Mixpanel/SEGMixpanelIntegration.m | 68 ++++++++-- .../Mixpanel/SEGMixpanelIntegrationTests.m | 126 +++++++++++++++++- 2 files changed, 183 insertions(+), 11 deletions(-) diff --git a/Analytics/Integrations/Mixpanel/SEGMixpanelIntegration.m b/Analytics/Integrations/Mixpanel/SEGMixpanelIntegration.m index 3c2df6c60..bbe9cfa7d 100644 --- a/Analytics/Integrations/Mixpanel/SEGMixpanelIntegration.m +++ b/Analytics/Integrations/Mixpanel/SEGMixpanelIntegration.m @@ -80,16 +80,44 @@ - (void)identify:(NSString *)userId traits:(NSDictionary *)traits options:(NSDic @"$name", @"name", @"$username", @"username", @"$phone", @"phone", nil]; - NSDictionary *mappedTraits = [SEGAnalyticsIntegration map:traits withMap:map]; - // Register the mapped traits. - [[self.mixpanelClass sharedInstance] registerSuperProperties:mappedTraits]; + if ([self setAllTraitsByDefault]) { + NSDictionary *mappedTraits = [SEGAnalyticsIntegration map:traits withMap:map]; - // Mixpanel also has a people API that works seperately, so we set the traits for it as well. - if ([(NSNumber *)[self.settings objectForKey:@"people"] boolValue]) { - // You'll notice that we could also have done: [self.mixpanelClass.sharedInstance.people set:mappedTraits]; - // Using methods instead of properties directly lets us mock them in tests, which is why we use the syntax below. - [[[self.mixpanelClass sharedInstance] people] set:mappedTraits]; + // Register the mapped traits. + [[self.mixpanelClass sharedInstance] registerSuperProperties:mappedTraits]; + + // Mixpanel also has a people API that works seperately, so we set the traits for it as well. + if ([self peopleEnabled]) { + // You'll notice that we could also have done: [self.mixpanelClass.sharedInstance.people set:mappedTraits]; + // Using methods instead of properties directly lets us mock them in tests, which is why we use the syntax below. + [[[self.mixpanelClass sharedInstance] people] set:mappedTraits]; + } + + return; + } + + NSDictionary *mixpanelOptions = [self mixpanelOptions:options]; + if (!mixpanelOptions) { + return; + } + + NSArray *superProperties = [mixpanelOptions objectForKey:@"superProperties"]; + NSMutableDictionary *superPropertyTraits = [NSMutableDictionary dictionaryWithCapacity:superProperties.count]; + for (NSString *superProperty in superProperties) { + superPropertyTraits[superProperty] = traits[superProperty]; + } + NSDictionary *mappedSuperProperties = [SEGAnalyticsIntegration map:superPropertyTraits withMap:map]; + [[self.mixpanelClass sharedInstance] registerSuperProperties:mappedSuperProperties]; + + if ([self peopleEnabled]) { + NSArray *peopleProperties = [mixpanelOptions objectForKey:@"peopleProperties"]; + NSMutableDictionary *peoplePropertyTraits = [NSMutableDictionary dictionaryWithCapacity:peopleProperties.count]; + for (NSString *peopleProperty in peopleProperties) { + peoplePropertyTraits[peopleProperty] = traits[peopleProperty]; + } + NSDictionary *mappedPeopleProperties = [SEGAnalyticsIntegration map:peoplePropertyTraits withMap:map]; + [[[self.mixpanelClass sharedInstance] people] set:mappedPeopleProperties]; } } @@ -99,7 +127,7 @@ - (void)track:(NSString *)event properties:(NSDictionary *)properties options:(N [[self.mixpanelClass sharedInstance] track:event properties:properties]; // Don't go any further if Mixpanel people is disabled. - if (![(NSNumber *)[self.settings objectForKey:@"people"] boolValue]) { + if (![self peopleEnabled]) { return; } @@ -160,6 +188,28 @@ - (BOOL)eventShouldIncrement:(NSString *)event return NO; } +// Return true the project has the People feature enabled. +- (BOOL)peopleEnabled +{ + return [(NSNumber *)[self.settings objectForKey:@"people"] boolValue]; +} + +// Return true if all traits should be set by default. +- (BOOL)setAllTraitsByDefault +{ + return [(NSNumber *)[self.settings objectForKey:@"setAllTraitsByDefault"] boolValue]; +} + +// Return true if all traits should be set by default. +- (NSDictionary *)mixpanelOptions:(NSDictionary *)options +{ + NSDictionary *integrations = [options objectForKey:@"integrations"]; + if (integrations) { + return [integrations objectForKey:@"Mixpanel"]; + } + return nil; +} + - (void)reset { [[self.mixpanelClass sharedInstance] flush]; diff --git a/iOS Tests/Integrations/Mixpanel/SEGMixpanelIntegrationTests.m b/iOS Tests/Integrations/Mixpanel/SEGMixpanelIntegrationTests.m index d69c94af6..0dc90eb71 100644 --- a/iOS Tests/Integrations/Mixpanel/SEGMixpanelIntegrationTests.m +++ b/iOS Tests/Integrations/Mixpanel/SEGMixpanelIntegrationTests.m @@ -78,6 +78,11 @@ - (void)testFlush - (void)testIdentify { + [_integration setSettings:@{ + @"token" : @"foo", + @"setAllTraitsByDefault" : @1 + }]; + [_integration identify:@"foo" traits:@{ @"bar" : @"baz" } options:@{}]; [verifyCount(_mixpanelMock, times(1)) identify:@"foo"]; @@ -89,7 +94,8 @@ - (void)testIdentifyWithPeople { [_integration setSettings:@{ @"token" : @"foo", - @"people" : @1 + @"people" : @1, + @"setAllTraitsByDefault" : @1 }]; [_integration identify:@"foo" traits:@{ @"bar" : @"baz" } options:@{}]; @@ -99,8 +105,27 @@ - (void)testIdentifyWithPeople [verifyCount(_mixpanelPeopleMock, times(1)) set:@{ @"bar" : @"baz" }]; } -- (void)testIdentifyWithTraits +- (void)testIdentifyWithPeopleAndWithoutSettingTraits { + [_integration setSettings:@{ + @"token" : @"foo", + @"people" : @1, + @"setAllTraitsByDefault" : @0 + }]; + [_integration identify:@"foo" traits:@{ @"bar" : @"baz" } options:@{}]; + + [verifyCount(_mixpanelMock, times(1)) identify:@"foo"]; + [verifyCount(_mixpanelMock, times(0)) registerSuperProperties:anything()]; + [verifyCount(_mixpanelPeopleMock, times(0)) set:anything()]; +} + +- (void)testIdentifyWithMappedTraits +{ + [_integration setSettings:@{ + @"token" : @"foo", + @"setAllTraitsByDefault" : @1 + }]; + [_integration identify:@"foo" traits:@{ @"firstName" : @"bar", @@ -127,6 +152,103 @@ - (void)testIdentifyWithTraits }]; } +- (void)testIdentifyWithMappedPropertiesAndSuperProperties +{ + [_integration setSettings:@{ + @"token" : @"foo", + @"people" : @1, + @"setAllTraitsByDefault" : @0 + }]; + + [_integration identify:@"foo" + traits:@{ + @"firstName" : @"bar", + @"lastName" : @"baz", + @"createdAt" : @"qaz", + @"lastSeen" : @"foobar", + @"email" : @"barbaz", + @"name" : @"bazqaz", + @"username" : @"foobarbaz", + @"phone" : @"barbazqaz" + } + options:@{ + @"integrations" : @{ + @"Mixpanel" : @{ + @"superProperties" : @[ @"firstName" ], + @"peopleProperties" : @[ @"lastName" ], + } + } + }]; + + [verifyCount(_mixpanelMock, times(1)) identify:@"foo"]; + [verifyCount(_mixpanelMock, times(1)) registerSuperProperties:@{ + @"$first_name" : @"bar" + }]; + [verifyCount(_mixpanelPeopleMock, times(1)) set:@{ + @"$last_name" : @"baz" + }]; +} + +- (void)testIdentifyWithoutSetAllTraitsAndNoMappedTraits +{ + [_integration setSettings:@{ + @"token" : @"foo", + @"people" : @1, + @"setAllTraitsByDefault" : @0 + }]; + + [_integration identify:@"foo" + traits:@{ + @"firstName" : @"bar", + @"lastName" : @"baz", + @"createdAt" : @"qaz", + @"lastSeen" : @"foobar", + @"email" : @"barbaz", + @"name" : @"bazqaz", + @"username" : @"foobarbaz", + @"phone" : @"barbazqaz" + } + options:@{ + @"integrations" : @{ + @"Mixpanel" : @{} + } + }]; + + [verifyCount(_mixpanelMock, times(1)) identify:@"foo"]; + [verifyCount(_mixpanelMock, times(1)) registerSuperProperties:anything()]; + [verifyCount(_mixpanelPeopleMock, times(1)) set:anything()]; +} + + +- (void)testIdentifyWithoutSetAllTraitsAndNoMixpanelOptions +{ + [_integration setSettings:@{ + @"token" : @"foo", + @"people" : @1, + @"setAllTraitsByDefault" : @0 + }]; + + [_integration identify:@"foo" + traits:@{ + @"firstName" : @"bar", + @"lastName" : @"baz", + @"createdAt" : @"qaz", + @"lastSeen" : @"foobar", + @"email" : @"barbaz", + @"name" : @"bazqaz", + @"username" : @"foobarbaz", + @"phone" : @"barbazqaz" + } + options:@{ + @"integrations" : @{} + }]; + + [verifyCount(_mixpanelMock, times(1)) identify:@"foo"]; + [verifyCount(_mixpanelMock, times(0)) registerSuperProperties:anything()]; + [verifyCount(_mixpanelPeopleMock, times(0)) set:anything()]; +} + + - (void)testTrack { [_integration track:@"foo" properties:@{ @"bar" : @"baz" } options:nil];