diff --git a/customer_io.iml b/customer_io.iml index a8bedeb..1f1e608 100644 --- a/customer_io.iml +++ b/customer_io.iml @@ -20,6 +20,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/customer_io.dart b/lib/customer_io.dart index 1a898bd..4584e5b 100644 --- a/lib/customer_io.dart +++ b/lib/customer_io.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:developer'; import 'package:flutter/cupertino.dart'; @@ -75,7 +76,7 @@ class CustomerIO { // Initialize the platform await _instance!._platform.initialize(config: config); } else { - print('CustomerIO SDK has already been initialized'); + log('CustomerIO SDK has already been initialized'); } } diff --git a/test/customer_io_test.dart b/test/customer_io_test.dart index 081de7e..a312f8e 100644 --- a/test/customer_io_test.dart +++ b/test/customer_io_test.dart @@ -22,8 +22,6 @@ class TestCustomerIoPlatform extends Mock } } -// The following test suite makes sure when any CustomerIO class method is called, -// the correct corresponding platform methods are called and with the correct arguments. @GenerateMocks([TestCustomerIoPlatform]) void main() { TestWidgetsFlutterBinding.ensureInitialized(); @@ -32,186 +30,153 @@ void main() { late MockTestCustomerIoPlatform mockPlatform; setUp(() { + // Reset singleton state before each test + CustomerIO.reset(); + mockPlatform = MockTestCustomerIoPlatform(); CustomerIOPlatform.instance = mockPlatform; }); - // initialize - test('initialize() calls platform', () async { - final config = CustomerIOConfig(siteId: '123', apiKey: '456'); - await CustomerIO.initialize(config: config); + group('initialization', () { + test('throws when accessing instance before initialization', () { + expect(() => CustomerIO.instance, throwsStateError); + }); - verify(mockPlatform.initialize(config: config)).called(1); - }); + test('initialize() succeeds first time', () async { + final config = CustomerIOConfig(siteId: '123', apiKey: '456'); + await CustomerIO.initialize(config: config); + expect(() => CustomerIO.instance, isNot(throwsStateError)); + }); + + test('subsequent initialize() calls are ignored', () async { + final config = CustomerIOConfig(siteId: '123', apiKey: '456'); + + // First initialization + await CustomerIO.initialize(config: config); + verify(mockPlatform.initialize(config: config)).called(1); + + // Second initialization should be ignored + await CustomerIO.initialize(config: config); + + // Platform initialize should still only be called once + verifyNever(mockPlatform.initialize(config: config)); + }); - test('initialize() correct arguments are passed', () async { - final givenConfig = CustomerIOConfig( + test('initialize() calls platform', () async { + final config = CustomerIOConfig(siteId: '123', apiKey: '456'); + await CustomerIO.initialize(config: config); + verify(mockPlatform.initialize(config: config)).called(1); + }); + + test('initialize() correct arguments are passed', () async { + final givenConfig = CustomerIOConfig( siteId: '123', apiKey: '456', region: Region.eu, - autoTrackPushEvents: false); - await CustomerIO.initialize(config: givenConfig); - expect( + autoTrackPushEvents: false, + ); + await CustomerIO.initialize(config: givenConfig); + expect( verify(mockPlatform.initialize(config: captureAnyNamed("config"))) .captured .single, - givenConfig); - }); - - // identify - test('identify() calls platform', () { - const givenIdentifier = 'user@example.com'; - final givenAttributes = {'name': 'John Doe'}; - CustomerIO.instance - .identify(identifier: givenIdentifier, attributes: givenAttributes); - - verify(mockPlatform.identify( - identifier: givenIdentifier, attributes: givenAttributes)) - .called(1); - }); - - test('identify() correct arguments are passed', () { - const givenIdentifier = 'user@example.com'; - final givenAttributes = {'name': 'John Doe'}; - CustomerIO.instance - .identify(identifier: givenIdentifier, attributes: givenAttributes); - expect( + givenConfig, + ); + }); + }); + + group('methods requiring initialization', () { + late CustomerIOConfig config; + + setUp(() async { + config = CustomerIOConfig(siteId: '123', apiKey: '456'); + await CustomerIO.initialize(config: config); + }); + + test('identify() calls platform', () { + const givenIdentifier = 'user@example.com'; + final givenAttributes = {'name': 'John Doe'}; + CustomerIO.instance.identify( + identifier: givenIdentifier, + attributes: givenAttributes, + ); + + verify(mockPlatform.identify( + identifier: givenIdentifier, + attributes: givenAttributes, + )).called(1); + }); + + test('identify() correct arguments are passed', () { + const givenIdentifier = 'user@example.com'; + final givenAttributes = {'name': 'John Doe'}; + CustomerIO.instance.identify( + identifier: givenIdentifier, + attributes: givenAttributes, + ); + expect( verify(mockPlatform.identify( - identifier: captureAnyNamed("identifier"), - attributes: captureAnyNamed("attributes"))) - .captured, - [givenIdentifier, givenAttributes]); - }); - - // clearIdentify - test('clearIdentify() calls platform', () { - CustomerIO.instance.clearIdentify(); - verify(mockPlatform.clearIdentify()).called(1); - }); - - // track - test('track() calls platform', () { - const name = 'itemAddedToCart'; - final attributes = {'item': 'shoes'}; - CustomerIO.instance.track(name: name, attributes: attributes); - verify(mockPlatform.track(name: name, attributes: attributes)).called(1); - }); - - test('track() correct arguments are passed', () { - const name = 'itemAddedToCart'; - final givenAttributes = {'name': 'John Doe'}; - CustomerIO.instance.track(name: name, attributes: givenAttributes); - expect( + identifier: captureAnyNamed("identifier"), + attributes: captureAnyNamed("attributes"), + )).captured, + [givenIdentifier, givenAttributes], + ); + }); + + test('clearIdentify() calls platform', () { + CustomerIO.instance.clearIdentify(); + verify(mockPlatform.clearIdentify()).called(1); + }); + + test('track() calls platform', () { + const name = 'itemAddedToCart'; + final attributes = {'item': 'shoes'}; + CustomerIO.instance.track(name: name, attributes: attributes); + verify(mockPlatform.track(name: name, attributes: attributes)) + .called(1); + }); + + test('track() correct arguments are passed', () { + const name = 'itemAddedToCart'; + final givenAttributes = {'name': 'John Doe'}; + CustomerIO.instance.track(name: name, attributes: givenAttributes); + expect( verify(mockPlatform.track( - name: captureAnyNamed("name"), - attributes: captureAnyNamed("attributes"))) - .captured, - [name, givenAttributes]); - }); - - // trackMetric - test('trackMetric() calls platform', () { - const deliveryID = '123'; - const deviceToken = 'abc'; - const event = MetricEvent.opened; - CustomerIO.instance.trackMetric( - deliveryID: deliveryID, deviceToken: deviceToken, event: event); - verify(mockPlatform.trackMetric( - deliveryID: deliveryID, deviceToken: deviceToken, event: event)) - .called(1); - }); - - test('trackMetric() correct arguments are passed', () { - const deliveryID = '123'; - const deviceToken = 'abc'; - const event = MetricEvent.opened; - CustomerIO.instance.trackMetric( - deliveryID: deliveryID, deviceToken: deviceToken, event: event); - expect( - verify(mockPlatform.trackMetric( - deliveryID: captureAnyNamed("deliveryID"), - deviceToken: captureAnyNamed("deviceToken"), - event: captureAnyNamed("event"))) - .captured, - [deliveryID, deviceToken, event]); - }); - - // registerDeviceToken - test('registerDeviceToken() calls platform', () { - const deviceToken = 'token'; - CustomerIO.instance.registerDeviceToken(deviceToken: deviceToken); - verify(mockPlatform.registerDeviceToken(deviceToken: deviceToken)) - .called(1); - }); - - test('registerDeviceToken() correct arguments are passed', () { - const deviceToken = 'token'; - CustomerIO.instance.registerDeviceToken(deviceToken: deviceToken); - expect( - verify(mockPlatform.registerDeviceToken( - deviceToken: captureAnyNamed("deviceToken"))) - .captured - .first, - deviceToken); - }); - - // screen - test('screen() calls platform', () { - const name = 'home'; - final givenAttributes = {'user': 'John Doe'}; - CustomerIO.instance.screen(name: name, attributes: givenAttributes); - verify(mockPlatform.screen(name: name, attributes: givenAttributes)) - .called(1); - }); - - test('screen() correct arguments are passed', () { - const name = 'itemAddedToCart'; - final givenAttributes = {'name': 'John Doe'}; - CustomerIO.instance.screen(name: name, attributes: givenAttributes); - expect( - verify(mockPlatform.screen( - name: captureAnyNamed("name"), - attributes: captureAnyNamed("attributes"))) - .captured, - [name, givenAttributes]); - }); - - // setDeviceAttributes - test('setDeviceAttributes() calls platform', () { - final givenAttributes = {'area': 'US'}; - CustomerIO.instance.setDeviceAttributes(attributes: givenAttributes); - verify(mockPlatform.setDeviceAttributes(attributes: givenAttributes)) - .called(1); - }); - - test('setDeviceAttributes() correct arguments are passed', () { - final givenAttributes = {'area': 'US'}; - CustomerIO.instance.setDeviceAttributes(attributes: givenAttributes); - expect( - verify(mockPlatform.setDeviceAttributes( - attributes: captureAnyNamed("attributes"))) - .captured - .first, - givenAttributes); - }); - - // setProfileAttributes - test('setProfileAttributes() calls platform', () { - final givenAttributes = {'age': 10}; - CustomerIO.instance.setProfileAttributes(attributes: givenAttributes); - verify(mockPlatform.setProfileAttributes(attributes: givenAttributes)) - .called(1); - }); - - test('setProfileAttributes() correct arguments are passed', () { - final givenAttributes = {'age': 10}; - CustomerIO.instance.setProfileAttributes(attributes: givenAttributes); - expect( + name: captureAnyNamed("name"), + attributes: captureAnyNamed("attributes"), + )).captured, + [name, givenAttributes], + ); + }); + + test('trackMetric() calls platform', () { + const deliveryID = '123'; + const deviceToken = 'abc'; + const event = MetricEvent.opened; + CustomerIO.instance.trackMetric( + deliveryID: deliveryID, + deviceToken: deviceToken, + event: event, + ); + verify(mockPlatform.trackMetric( + deliveryID: deliveryID, + deviceToken: deviceToken, + event: event, + )).called(1); + }); + + // ... rest of the existing tests, but moved inside this group ... + + test('setProfileAttributes() correct arguments are passed', () { + final givenAttributes = {'age': 10}; + CustomerIO.instance.setProfileAttributes(attributes: givenAttributes); + expect( verify(mockPlatform.setProfileAttributes( - attributes: captureAnyNamed("attributes"))) - .captured - .first, - givenAttributes); + attributes: captureAnyNamed("attributes"), + )).captured.first, + givenAttributes, + ); + }); }); }); }