Files
sxchnge/frontend/packages/sxchnge_auth/test/verification_test.dart
T

124 lines
4.0 KiB
Dart

import 'dart:async';
import 'package:flutter_test/flutter_test.dart';
import 'package:sxchnge_auth/sxchnge_auth.dart';
class PendingService implements VerificationService {
final pending = Completer<VerificationResult>();
int calls = 0;
String? email;
String? locale;
@override
Future<VerificationResult> send({
required String email,
required String locale,
}) {
calls++;
this.email = email;
this.locale = locale;
return pending.future;
}
@override
Future<VerificationResult> confirm({required String token}) {
calls++;
return pending.future;
}
}
void main() {
for (final scenario in {
'demo-valid': VerificationStatus.verified,
'demo-expired': VerificationStatus.expired,
'bad': VerificationStatus.invalid,
'': VerificationStatus.invalid,
'demo-internal': VerificationStatus.error,
}.entries) {
test('confirmation maps ${scenario.key} to ${scenario.value}', () async {
final provider = VerificationProvider(
const DummyVerificationService(delay: Duration.zero),
);
addTearDown(provider.dispose);
await provider.confirm(scenario.key);
expect(provider.state.status, scenario.value);
expect(
provider.state.result?.verifiedEmail,
scenario.value == VerificationStatus.verified
? 'alex@example.com'
: null,
);
expect(
provider.state.isSimulated,
scenario.value == VerificationStatus.verified,
);
});
}
test(
'send trims email, forwards locale and suppresses duplicate requests',
() async {
final service = PendingService();
final provider = VerificationProvider(service);
addTearDown(provider.dispose);
final first = provider.send(email: ' alex@example.com ', locale: 'ru');
expect(provider.state.status, VerificationStatus.sending);
await provider.send(email: 'other@example.com', locale: 'en');
expect(service.calls, 1);
expect(service.email, 'alex@example.com');
expect(service.locale, 'ru');
service.pending.complete(const VerificationResult(isSimulated: true));
await first;
expect(provider.state.status, VerificationStatus.sent);
expect(provider.state.isSimulated, isTrue);
},
);
test('reset discards late result', () async {
final service = PendingService();
final provider = VerificationProvider(service);
addTearDown(provider.dispose);
final operation = provider.confirm('token');
provider.reset();
service.pending.complete(const VerificationResult(isSimulated: true));
await operation;
expect(provider.state.status, VerificationStatus.idle);
expect(provider.state.result, isNull);
});
test(
'a later failed confirmation clears the previous verified identity',
() async {
final provider = VerificationProvider(
const DummyVerificationService(delay: Duration.zero),
);
addTearDown(provider.dispose);
await provider.confirm('demo-valid');
expect(provider.state.result?.verifiedEmail, 'alex@example.com');
final operation = provider.confirm('bad');
expect(provider.state.result, isNull);
await operation;
expect(provider.state.result, isNull);
},
);
test('dispose discards late exception', () async {
final service = PendingService();
final provider = VerificationProvider(service);
final operation = provider.confirm('token');
provider.dispose();
service.pending.completeError(StateError('private error'));
await operation;
});
test(
'send errors are internal errors even for token exception types',
() async {
final provider = VerificationProvider(
const DummyVerificationService(
delay: Duration.zero,
sendFailure: VerificationError.expired,
),
);
addTearDown(provider.dispose);
await provider.send(email: 'alex@example.com', locale: 'en');
expect(provider.state.status, VerificationStatus.error);
},
);
}