205 lines
6.5 KiB
Dart
205 lines
6.5 KiB
Dart
|
|
import 'dart:typed_data';
|
||
|
|
|
||
|
|
import 'package:flutter_test/flutter_test.dart';
|
||
|
|
import 'package:halkyon_learn_flutter/src/core/router/route_paths.dart';
|
||
|
|
import 'package:halkyon_learn_flutter/src/feature/auth/model/auth_status.dart';
|
||
|
|
import 'package:halkyon_learn_flutter/src/feature/profile/data/profile_repository.dart';
|
||
|
|
import 'package:halkyon_learn_flutter/src/feature/profile/model/public_profile.dart';
|
||
|
|
import 'package:material_ui/material_ui.dart';
|
||
|
|
|
||
|
|
import '../../support/fake_auth_gateway.dart';
|
||
|
|
import '../../support/fake_file_picker.dart';
|
||
|
|
import '../../support/fake_profile_gateway.dart';
|
||
|
|
import '../../support/pump_app.dart';
|
||
|
|
import '../../support/test_dependencies.dart';
|
||
|
|
|
||
|
|
void main() {
|
||
|
|
/// Opens the Profile tab of a person with an identity, whose profile the
|
||
|
|
/// instance answers through [profiles].
|
||
|
|
Future<void> showProfile(
|
||
|
|
WidgetTester tester,
|
||
|
|
FakeProfileGateway profiles, {
|
||
|
|
bool identified = true,
|
||
|
|
FakeFilePicker? files,
|
||
|
|
}) async {
|
||
|
|
tester.view.physicalSize = const Size(1000, 1800);
|
||
|
|
tester.view.devicePixelRatio = 1;
|
||
|
|
addTearDown(tester.view.reset);
|
||
|
|
await pumpApp(
|
||
|
|
tester,
|
||
|
|
testDependencies(
|
||
|
|
authGateway: FakeAuthGateway(
|
||
|
|
status: SignedIn(
|
||
|
|
authUserId: 'github-person',
|
||
|
|
isIdentified: identified,
|
||
|
|
),
|
||
|
|
),
|
||
|
|
profileGateway: profiles,
|
||
|
|
files: files,
|
||
|
|
),
|
||
|
|
location: RoutePaths.profile,
|
||
|
|
);
|
||
|
|
await tester.pumpAndSettle();
|
||
|
|
}
|
||
|
|
|
||
|
|
Finder field(String label) => find.widgetWithText(TextField, label);
|
||
|
|
|
||
|
|
testWidgets('a person with an identity writes a public profile and saves '
|
||
|
|
'it, then sees the address others find them by', (tester) async {
|
||
|
|
final profiles = FakeProfileGateway();
|
||
|
|
await showProfile(tester, profiles);
|
||
|
|
|
||
|
|
expect(find.text('Public profile'), findsOneWidget);
|
||
|
|
await tester.enterText(field('Display name'), 'Tizian');
|
||
|
|
await tester.enterText(field('Handle'), 'raisondetredev');
|
||
|
|
await tester.enterText(field('Bio'), 'Learning Japanese.');
|
||
|
|
await tester.tap(find.text('Add link'));
|
||
|
|
await tester.pumpAndSettle();
|
||
|
|
await tester.enterText(
|
||
|
|
find.widgetWithText(TextField, 'https://…'),
|
||
|
|
'https://halkyon.app',
|
||
|
|
);
|
||
|
|
await tester.tap(find.text('Save'));
|
||
|
|
await tester.pumpAndSettle();
|
||
|
|
|
||
|
|
expect(find.text('Profile saved.'), findsOneWidget);
|
||
|
|
expect(
|
||
|
|
find.text('Others find you as @raisondetredev@halkyon.eu'),
|
||
|
|
findsOneWidget,
|
||
|
|
);
|
||
|
|
expect(profiles.profile!.links, ['https://halkyon.app']);
|
||
|
|
expect(profiles.profile!.displayName, 'Tizian');
|
||
|
|
});
|
||
|
|
|
||
|
|
testWidgets('a handle someone else has is refused, said under it', (
|
||
|
|
tester,
|
||
|
|
) async {
|
||
|
|
await showProfile(tester, FakeProfileGateway(taken: {'Tizian'}));
|
||
|
|
|
||
|
|
await tester.enterText(field('Handle'), 'tizian');
|
||
|
|
await tester.tap(find.text('Save'));
|
||
|
|
await tester.pumpAndSettle();
|
||
|
|
|
||
|
|
expect(find.text('Someone else has this handle.'), findsOneWidget);
|
||
|
|
});
|
||
|
|
|
||
|
|
testWidgets('once its person has published, the handle is fixed and the '
|
||
|
|
'profile stays', (tester) async {
|
||
|
|
await showProfile(
|
||
|
|
tester,
|
||
|
|
FakeProfileGateway(
|
||
|
|
profile: const PublicProfile(
|
||
|
|
handle: 'raisondetredev',
|
||
|
|
address: 'raisondetredev@halkyon.eu',
|
||
|
|
handleFixed: true,
|
||
|
|
),
|
||
|
|
),
|
||
|
|
);
|
||
|
|
|
||
|
|
expect(
|
||
|
|
find.text('Fixed since you published: others refer to it.'),
|
||
|
|
findsOneWidget,
|
||
|
|
);
|
||
|
|
expect(
|
||
|
|
tester.widget<TextField>(field('Handle')).readOnly,
|
||
|
|
isTrue,
|
||
|
|
);
|
||
|
|
expect(find.text('Remove profile'), findsNothing);
|
||
|
|
});
|
||
|
|
|
||
|
|
testWidgets('removing a profile asks first, then frees its handle', (
|
||
|
|
tester,
|
||
|
|
) async {
|
||
|
|
final profiles = FakeProfileGateway(
|
||
|
|
profile: const PublicProfile(
|
||
|
|
handle: 'raisondetredev',
|
||
|
|
address: 'raisondetredev@halkyon.eu',
|
||
|
|
),
|
||
|
|
);
|
||
|
|
await showProfile(tester, profiles);
|
||
|
|
|
||
|
|
await tester.tap(find.text('Remove profile'));
|
||
|
|
await tester.pumpAndSettle();
|
||
|
|
expect(find.text('Remove your public profile?'), findsOneWidget);
|
||
|
|
await tester.tap(find.text('Remove profile').last);
|
||
|
|
await tester.pumpAndSettle();
|
||
|
|
|
||
|
|
expect(find.text('Profile removed.'), findsOneWidget);
|
||
|
|
expect(profiles.profile, isNull);
|
||
|
|
});
|
||
|
|
|
||
|
|
testWidgets('a saved profile takes a picture as its avatar, and gives it '
|
||
|
|
'up', (tester) async {
|
||
|
|
final profiles = FakeProfileGateway(
|
||
|
|
profile: const PublicProfile(
|
||
|
|
handle: 'raisondetredev',
|
||
|
|
address: 'raisondetredev@halkyon.eu',
|
||
|
|
),
|
||
|
|
);
|
||
|
|
final files = FakeFilePicker()
|
||
|
|
..next = (name: 'me.jpg', bytes: Uint8List.fromList([1, 2, 3]));
|
||
|
|
await showProfile(tester, profiles, files: files);
|
||
|
|
|
||
|
|
await tester.tap(find.text('Choose picture'));
|
||
|
|
await tester.pumpAndSettle();
|
||
|
|
|
||
|
|
expect(profiles.avatars.single, [1, 2, 3]);
|
||
|
|
expect(files.asked.single, contains('jpg'));
|
||
|
|
expect(find.text('Profile saved.'), findsOneWidget);
|
||
|
|
await tester.tap(find.text('Remove picture'));
|
||
|
|
await tester.pumpAndSettle();
|
||
|
|
expect(profiles.profile!.avatarUrl, isNull);
|
||
|
|
expect(find.text('Remove picture'), findsNothing);
|
||
|
|
});
|
||
|
|
|
||
|
|
testWidgets('a profile not yet saved has no picture to choose', (
|
||
|
|
tester,
|
||
|
|
) async {
|
||
|
|
await showProfile(tester, FakeProfileGateway());
|
||
|
|
|
||
|
|
expect(find.text('Save your profile to add a picture.'), findsOneWidget);
|
||
|
|
expect(find.text('Choose picture'), findsNothing);
|
||
|
|
});
|
||
|
|
|
||
|
|
testWidgets('an anonymous person is told how to have one', (tester) async {
|
||
|
|
await showProfile(tester, FakeProfileGateway(), identified: false);
|
||
|
|
|
||
|
|
expect(
|
||
|
|
find.text('Sign in with GitHub to have a public profile and publish.'),
|
||
|
|
findsOneWidget,
|
||
|
|
);
|
||
|
|
expect(find.text('Public profile'), findsNothing);
|
||
|
|
});
|
||
|
|
|
||
|
|
testWidgets('without the instance, it says so and tries again', (
|
||
|
|
tester,
|
||
|
|
) async {
|
||
|
|
final profiles = FakeProfileGateway()..fail = Exception('offline');
|
||
|
|
await showProfile(tester, profiles);
|
||
|
|
|
||
|
|
expect(
|
||
|
|
find.text("Your public profile can't be reached right now."),
|
||
|
|
findsOneWidget,
|
||
|
|
);
|
||
|
|
profiles.fail = null;
|
||
|
|
await tester.tap(find.text('Retry'));
|
||
|
|
await tester.pumpAndSettle();
|
||
|
|
expect(field('Handle'), findsOneWidget);
|
||
|
|
});
|
||
|
|
|
||
|
|
test(
|
||
|
|
'the repository leaves blank links out and trims what it saves',
|
||
|
|
() async {
|
||
|
|
final profiles = FakeProfileGateway();
|
||
|
|
await ProfileRepository(profiles).save(
|
||
|
|
handle: ' tizian ',
|
||
|
|
displayName: ' Tizian ',
|
||
|
|
bio: '',
|
||
|
|
links: ['', ' https://halkyon.app '],
|
||
|
|
);
|
||
|
|
|
||
|
|
expect(profiles.profile!.handle, 'tizian');
|
||
|
|
expect(profiles.profile!.links, ['https://halkyon.app']);
|
||
|
|
},
|
||
|
|
);
|
||
|
|
}
|