blob: 3d55fe27d7b0ee41dd4b5982a488072e6a3b0b1d [file] [log] [blame]
// Copyright 2013 The Flutter 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 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:in_app_purchase_storekit/src/channel.dart';
import 'package:in_app_purchase_storekit/store_kit_wrappers.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final FakeStoreKitPlatform fakeStoreKitPlatform = FakeStoreKitPlatform();
setUpAll(() {
_ambiguate(TestDefaultBinaryMessengerBinding.instance)!
.defaultBinaryMessenger
.setMockMethodCallHandler(
SystemChannels.platform, fakeStoreKitPlatform.onMethodCall);
});
test(
'handlePaymentQueueDelegateCallbacks should call SKPaymentQueueDelegateWrapper.shouldContinueTransaction',
() async {
final SKPaymentQueueWrapper queue = SKPaymentQueueWrapper();
final TestPaymentQueueDelegate testDelegate = TestPaymentQueueDelegate();
await queue.setDelegate(testDelegate);
final Map<String, dynamic> arguments = <String, dynamic>{
'storefront': <String, String>{
'countryCode': 'USA',
'identifier': 'unique_identifier',
},
'transaction': <String, dynamic>{
'payment': <String, dynamic>{
'productIdentifier': 'product_identifier',
}
},
};
final Object? result = await queue.handlePaymentQueueDelegateCallbacks(
MethodCall('shouldContinueTransaction', arguments),
);
expect(result, false);
expect(
testDelegate.log,
<Matcher>{
equals('shouldContinueTransaction'),
},
);
});
test(
'handlePaymentQueueDelegateCallbacks should call SKPaymentQueueDelegateWrapper.shouldShowPriceConsent',
() async {
final SKPaymentQueueWrapper queue = SKPaymentQueueWrapper();
final TestPaymentQueueDelegate testDelegate = TestPaymentQueueDelegate();
await queue.setDelegate(testDelegate);
final bool result = (await queue.handlePaymentQueueDelegateCallbacks(
const MethodCall('shouldShowPriceConsent'),
))! as bool;
expect(result, false);
expect(
testDelegate.log,
<Matcher>{
equals('shouldShowPriceConsent'),
},
);
});
test(
'handleObserverCallbacks should call SKTransactionObserverWrapper.restoreCompletedTransactionsFailed',
() async {
final SKPaymentQueueWrapper queue = SKPaymentQueueWrapper();
final TestTransactionObserverWrapper testObserver =
TestTransactionObserverWrapper();
queue.setTransactionObserver(testObserver);
final Map<dynamic, dynamic> arguments = <dynamic, dynamic>{
'code': 100,
'domain': 'domain',
'userInfo': <String, dynamic>{'error': 'underlying_error'},
};
await queue.handleObserverCallbacks(
MethodCall('restoreCompletedTransactionsFailed', arguments),
);
expect(
testObserver.log,
<Matcher>{
equals('restoreCompletedTransactionsFailed'),
},
);
});
}
class TestTransactionObserverWrapper extends SKTransactionObserverWrapper {
final List<String> log = <String>[];
@override
void updatedTransactions(
{required List<SKPaymentTransactionWrapper> transactions}) {
log.add('updatedTransactions');
}
@override
void removedTransactions(
{required List<SKPaymentTransactionWrapper> transactions}) {
log.add('removedTransactions');
}
@override
void restoreCompletedTransactionsFailed({required SKError error}) {
log.add('restoreCompletedTransactionsFailed');
}
@override
void paymentQueueRestoreCompletedTransactionsFinished() {
log.add('paymentQueueRestoreCompletedTransactionsFinished');
}
@override
bool shouldAddStorePayment(
{required SKPaymentWrapper payment, required SKProductWrapper product}) {
log.add('shouldAddStorePayment');
return false;
}
}
class TestPaymentQueueDelegate extends SKPaymentQueueDelegateWrapper {
final List<String> log = <String>[];
@override
bool shouldContinueTransaction(
SKPaymentTransactionWrapper transaction, SKStorefrontWrapper storefront) {
log.add('shouldContinueTransaction');
return false;
}
@override
bool shouldShowPriceConsent() {
log.add('shouldShowPriceConsent');
return false;
}
}
class FakeStoreKitPlatform {
FakeStoreKitPlatform() {
_ambiguate(TestDefaultBinaryMessengerBinding.instance)!
.defaultBinaryMessenger
.setMockMethodCallHandler(channel, onMethodCall);
}
// indicate if the payment queue delegate is registered
bool isPaymentQueueDelegateRegistered = false;
Future<dynamic> onMethodCall(MethodCall call) {
switch (call.method) {
case '-[SKPaymentQueue registerDelegate]':
isPaymentQueueDelegateRegistered = true;
return Future<void>.sync(() {});
case '-[SKPaymentQueue removeDelegate]':
isPaymentQueueDelegateRegistered = false;
return Future<void>.sync(() {});
}
return Future<dynamic>.error('method not mocked');
}
}
/// This allows a value of type T or T? to be treated as a value of type T?.
///
/// We use this so that APIs that have become non-nullable can still be used
/// with `!` and `?` on the stable branch.
T? _ambiguate<T>(T? value) => value;