blob: 9f2d705868828b00aeb3665098bd23ebe01c4bdf [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:mockito/mockito.dart';
import 'package:test/test.dart';
import 'package:flutter/services.dart';
import 'package:firebase_analytics/firebase_analytics.dart';
void main() {
group('filterOutNulls', () {
test('filters out null values', () {
final Map<String, dynamic> original = <String, dynamic>{
'a': 1,
'b': null,
'c': 'd'
};
final Map<String, dynamic> filtered = filterOutNulls(original);
expect(filtered, isNot(same(original)));
expect(original, <String, dynamic>{'a': 1, 'b': null, 'c': 'd'});
expect(filtered, <String, dynamic>{'a': 1, 'c': 'd'});
});
});
group('$FirebaseAnalytics', () {
FirebaseAnalytics analytics;
String invokedMethod;
dynamic arguments;
setUp(() {
final MockPlatformChannel mockChannel = new MockPlatformChannel();
invokedMethod = null;
arguments = null;
when(mockChannel.invokeMethod(any, any))
.thenAnswer((Invocation invocation) {
invokedMethod = invocation.positionalArguments[0];
arguments = invocation.positionalArguments[1];
return Future<void>.value();
});
analytics = new FirebaseAnalytics.private(mockChannel);
});
test('setUserId', () async {
await analytics.setUserId('test-user-id');
expect(invokedMethod, 'setUserId');
expect(arguments, 'test-user-id');
});
test('setCurrentScreen', () async {
await analytics.setCurrentScreen(
screenName: 'test-screen-name',
screenClassOverride: 'test-class-override');
expect(invokedMethod, 'setCurrentScreen');
expect(arguments, <String, String>{
'screenName': 'test-screen-name',
'screenClassOverride': 'test-class-override',
});
});
test('setUserProperty', () async {
await analytics.setUserProperty(name: 'test_name', value: 'test-value');
expect(invokedMethod, 'setUserProperty');
expect(arguments, <String, String>{
'name': 'test_name',
'value': 'test-value',
});
});
test('setUserProperty rejects invalid names', () async {
// invalid character
expect(analytics.setUserProperty(name: 'test-name', value: 'test-value'),
throwsArgumentError);
// non-alpha first character
expect(analytics.setUserProperty(name: '0test', value: 'test-value'),
throwsArgumentError);
// null
expect(analytics.setUserProperty(name: null, value: 'test-value'),
throwsArgumentError);
// blank
expect(analytics.setUserProperty(name: '', value: 'test-value'),
throwsArgumentError);
// reserved prefix
expect(
analytics.setUserProperty(name: 'firebase_test', value: 'test-value'),
throwsArgumentError);
});
test('setAnalyticsCollectionEnabled', () async {
await analytics.android.setAnalyticsCollectionEnabled(false);
expect(invokedMethod, 'setAnalyticsCollectionEnabled');
expect(arguments, false);
});
test('setMinimumSessionDuration', () async {
await analytics.android.setMinimumSessionDuration(123);
expect(invokedMethod, 'setMinimumSessionDuration');
expect(arguments, 123);
});
test('setSessionTimeoutDuration', () async {
await analytics.android.setSessionTimeoutDuration(234);
expect(invokedMethod, 'setSessionTimeoutDuration');
expect(arguments, 234);
});
});
group('$FirebaseAnalytics analytics events', () {
FirebaseAnalytics analytics;
String name;
Map<String, dynamic> parameters;
setUp(() {
final MockPlatformChannel mockChannel = new MockPlatformChannel();
name = null;
parameters = null;
when(mockChannel.invokeMethod('logEvent', any))
.thenAnswer((Invocation invocation) {
final Map<String, dynamic> args = invocation.positionalArguments[1];
name = args['name'];
parameters = args['parameters'];
expect(args.keys, unorderedEquals(<String>['name', 'parameters']));
return Future<void>.value();
});
when(mockChannel.invokeMethod(argThat(isNot('logEvent')), any))
.thenThrow(new ArgumentError('Only logEvent invocations expected'));
analytics = new FirebaseAnalytics.private(mockChannel);
});
test('logEvent log events', () async {
await analytics.logEvent(
name: 'test-event', parameters: <String, dynamic>{'a': 'b'});
expect(name, 'test-event');
expect(parameters, <String, dynamic>{'a': 'b'});
});
test('logEvent rejects events with reserved names', () async {
expect(analytics.logEvent(name: 'app_clear_data'), throwsArgumentError);
});
test('logEvent rejects events with reserved prefix', () async {
expect(analytics.logEvent(name: 'firebase_foo'), throwsArgumentError);
});
void smokeTest(String testFunctionName, Future<Null> testFunction()) {
test('$testFunctionName works', () async {
await testFunction();
expect(name, testFunctionName);
});
}
smokeTest('add_payment_info', () => analytics.logAddPaymentInfo());
smokeTest(
'add_to_cart',
() => analytics.logAddToCart(
itemId: 'test-id',
itemName: 'test-name',
itemCategory: 'test-category',
quantity: 5,
));
smokeTest(
'add_to_wishlist',
() => analytics.logAddToWishlist(
itemId: 'test-id',
itemName: 'test-name',
itemCategory: 'test-category',
quantity: 5,
));
smokeTest('app_open', () => analytics.logAppOpen());
smokeTest('begin_checkout', () => analytics.logBeginCheckout());
smokeTest(
'campaign_details',
() => analytics.logCampaignDetails(
source: 'test-source',
medium: 'test-medium',
campaign: 'test-campaign',
));
smokeTest(
'earn_virtual_currency',
() => analytics.logEarnVirtualCurrency(
virtualCurrencyName: 'bitcoin',
value: 34,
));
smokeTest('ecommerce_purchase', () => analytics.logEcommercePurchase());
smokeTest('generate_lead', () => analytics.logGenerateLead());
smokeTest(
'join_group',
() => analytics.logJoinGroup(
groupId: 'test-group-id',
));
smokeTest(
'level_up',
() => analytics.logLevelUp(
level: 56,
));
smokeTest('login', () => analytics.logLogin());
smokeTest(
'post_score',
() => analytics.logPostScore(
score: 34,
));
smokeTest(
'present_offer',
() => analytics.logPresentOffer(
itemId: 'test-id',
itemName: 'test-name',
itemCategory: 'test-category',
quantity: 5,
));
smokeTest('purchase_refund', () => analytics.logPurchaseRefund());
smokeTest(
'search',
() => analytics.logSearch(
searchTerm: 'test search term',
));
smokeTest(
'select_content',
() => analytics.logSelectContent(
contentType: 'test content type',
itemId: 'test item id',
));
smokeTest(
'share',
() => analytics.logShare(
contentType: 'test content type',
itemId: 'test item id',
));
smokeTest(
'sign_up',
() => analytics.logSignUp(
signUpMethod: 'test sign-up method',
));
smokeTest(
'spend_virtual_currency',
() => analytics.logSpendVirtualCurrency(
itemName: 'test-item-name',
virtualCurrencyName: 'bitcoin',
value: 345,
));
smokeTest('tutorial_begin', () => analytics.logTutorialBegin());
smokeTest('tutorial_complete', () => analytics.logTutorialComplete());
smokeTest(
'unlock_achievement',
() => analytics.logUnlockAchievement(
id: 'firebase analytics api coverage',
));
smokeTest(
'view_item',
() => analytics.logViewItem(
itemId: 'test-id',
itemName: 'test-name',
itemCategory: 'test-category',
));
smokeTest(
'view_item_list',
() => analytics.logViewItemList(
itemCategory: 'test-category',
));
smokeTest(
'view_search_results',
() => analytics.logViewSearchResults(
searchTerm: 'test search term',
));
void testRequiresValueAndCurrencyTogether(
String methodName, Future<Null> testFn()) {
test('$methodName requires value and currency together', () async {
try {
testFn();
fail('Expected ArgumentError');
} on ArgumentError catch (error) {
expect(error.message, valueAndCurrencyMustBeTogetherError);
}
});
}
testRequiresValueAndCurrencyTogether('logAddToCart', () {
return analytics.logAddToCart(
itemId: 'test-id',
itemName: 'test-name',
itemCategory: 'test-category',
quantity: 5,
value: 123.90,
);
});
testRequiresValueAndCurrencyTogether('logAddToWishlist', () {
return analytics.logAddToWishlist(
itemId: 'test-id',
itemName: 'test-name',
itemCategory: 'test-category',
quantity: 5,
value: 123.90,
);
});
testRequiresValueAndCurrencyTogether('logBeginCheckout', () {
return analytics.logBeginCheckout(
value: 123.90,
);
});
testRequiresValueAndCurrencyTogether('logEcommercePurchase', () {
return analytics.logEcommercePurchase(
value: 123.90,
);
});
testRequiresValueAndCurrencyTogether('logGenerateLead', () {
return analytics.logGenerateLead(
value: 123.90,
);
});
testRequiresValueAndCurrencyTogether('logPresentOffer', () {
return analytics.logPresentOffer(
itemId: 'test-id',
itemName: 'test-name',
itemCategory: 'test-category',
quantity: 5,
value: 123.90,
);
});
testRequiresValueAndCurrencyTogether('logPurchaseRefund', () {
return analytics.logPurchaseRefund(
value: 123.90,
);
});
testRequiresValueAndCurrencyTogether('logViewItem', () {
return analytics.logViewItem(
itemId: 'test-id',
itemName: 'test-name',
itemCategory: 'test-category',
value: 123.90,
);
});
});
}
class MockPlatformChannel extends Mock implements MethodChannel {}