Files
ReelShort/test/player/player_locked_auth_flow_test.dart

184 lines
4.9 KiB
Dart

import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:fruitshorts/core/data/models/drama.dart';
import 'package:fruitshorts/core/data/models/play_ticket.dart';
import 'package:fruitshorts/core/data/models/player_port.dart';
import 'package:fruitshorts/core/data/models/wallet.dart';
import 'package:fruitshorts/core/data/repositories/commerce_repository.dart';
import 'package:fruitshorts/core/data/repositories/playback_repository.dart';
import 'package:fruitshorts/core/data/services/android_picture_in_picture.dart';
import 'package:fruitshorts/core/data/services/playback_session.dart';
import 'package:fruitshorts/core/data/services/wallet_controller.dart';
import 'package:fruitshorts/pages/player/player_logic.dart';
import 'package:fruitshorts/pages/player/player_view.dart';
import '../support/fake_watch_history.dart';
const _lockedDrama = Drama(
id: 'locked',
title: 'Locked',
synopsis: 'synopsis',
posterUrl: '/files/locked.png',
episodes: [
Episode(
id: 'locked-1',
number: 1,
title: 'Locked episode',
isFree: false,
locked: true,
),
],
);
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
test('should_not_request_ticket_for_guest_on_locked_episode', () async {
final playback = FakePlaybackRepository();
final logic = _logic(playback, signedIn: false);
logic.attach(
const PlayerPage(drama: _lockedDrama, initialIndex: 0),
isMounted: () => true,
);
logic.start(
factory: (_) => _NoopPlayer(),
coordinator: PlaybackCoordinator(),
);
await _drain(logic);
expect(playback.requests, isEmpty);
expect(logic.session.isLocked, isTrue);
logic.dispose();
await _drain(logic);
});
test('should_request_ticket_after_user_is_signed_in', () async {
final playback = FakePlaybackRepository(
ticket: const PlayTicket(
episodeId: 'locked-1',
accessible: false,
accessType: PlayTicket.coinRequired,
unlockCoin: 30,
),
);
final logic = _logic(playback, signedIn: true);
logic.attach(
const PlayerPage(drama: _lockedDrama, initialIndex: 0),
isMounted: () => true,
);
logic.start(
factory: (_) => _NoopPlayer(),
coordinator: PlaybackCoordinator(),
);
await _drain(logic);
expect(playback.requests, ['locked-1']);
expect(logic.blockedEpisodeId, 'locked-1');
logic.dispose();
await _drain(logic);
});
test('should_resume_unlock_and_play_for_same_episode_after_login', () async {
var signedIn = false;
final playback = FakePlaybackRepository(
ticket: const PlayTicket(
episodeId: 'locked-1',
accessible: true,
accessType: 'ENTITLED',
playUrl: '/files/locked-1.mp4',
),
);
final logic = _logic(
playback,
signedIn: false,
isSignedIn: () => signedIn,
wallet: WalletController(_UnlockCommerceRepository()),
);
logic.attach(
const PlayerPage(drama: _lockedDrama, initialIndex: 0),
isMounted: () => true,
);
logic.start(
factory: (_) => _NoopPlayer(),
coordinator: PlaybackCoordinator(),
);
await _drain(logic);
expect(playback.requests, isEmpty);
expect(logic.blockedEpisodeId, 'locked-1');
signedIn = true;
final unlocked = await logic.unlockEpisode(0);
await _drain(logic);
expect(unlocked, isTrue);
expect(playback.requests, ['locked-1']);
expect(logic.session.active, isNotNull);
logic.dispose();
await _drain(logic);
});
}
PlayerLogic _logic(
PlaybackRepository playback, {
bool signedIn = true,
bool Function()? isSignedIn,
WalletController? wallet,
}) {
return PlayerLogic(
history: FakeWatchHistory(),
playback: playback,
wallet: wallet,
pictureInPicture: AndroidPictureInPicture(
channel: const MethodChannel('test/player_locked_auth_flow/pip'),
),
waitForFrame: () async {},
isSignedIn: isSignedIn ?? () => signedIn,
);
}
Future<void> _drain(PlayerLogic logic) async {
for (var attempt = 0; attempt < 4; attempt++) {
await pumpEventQueue();
await logic.session.playbackSettled;
await logic.session.preloadSettled;
}
}
class _NoopPlayer implements PlayerPort {
@override
Future<void> initialize() async {}
@override
Future<void> play() async {}
@override
Future<void> pause() async {}
@override
Future<void> dispose() async {}
}
class _UnlockCommerceRepository implements CommerceRepository {
@override
Future<WalletSnapshot> fetchWallet() async => const WalletSnapshot(
wallet: CoinWallet(
coinBalance: 100,
totalRechargedCoin: 0,
totalConsumedCoin: 0,
totalRefundedCoin: 0,
),
);
@override
Future<UnlockResult> unlock(String episodeId) async => const UnlockResult(
unlocked: true,
accessType: 'ENTITLED',
coinCost: 30,
coinBalance: 70,
);
}