Files
flutterApp/test/admin_settings_access_test.dart

235 lines
8.0 KiB
Dart

import 'dart:async';
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:maibu_satabot_v2/core/app/app_user_cubit.dart';
import 'package:maibu_satabot_v2/core/di/injection.dart';
import 'package:maibu_satabot_v2/core/domain/entities/user_entity.dart';
import 'package:maibu_satabot_v2/core/localization/app_localizations.dart';
import 'package:maibu_satabot_v2/core/localization/locale_cubit.dart';
import 'package:maibu_satabot_v2/core/theme/AppTheme.dart';
import 'package:maibu_satabot_v2/core/update/update_cubit.dart';
import 'package:maibu_satabot_v2/core/update/update_state.dart';
import 'package:maibu_satabot_v2/core/update/version_check_service.dart';
import 'package:maibu_satabot_v2/features/main_container/domain/tab_config.dart';
import 'package:maibu_satabot_v2/features/main_container/presentation/cubit/tab_config_cubit.dart';
import 'package:maibu_satabot_v2/features/main_container/presentation/main_wrapper.dart';
import 'package:maibu_satabot_v2/features/v2/device_list/presentation/float_bar/cubit/float_bar_setting_cubit.dart';
import 'package:maibu_satabot_v2/features/v2/device_list/presentation/float_bar/view/float_bar_widget.dart';
import 'package:maibu_satabot_v2/features/v2/my/presentation/pages/my_page_v2.dart';
import 'package:maibu_satabot_v2/features/v2/my/presentation/pages/system_settings_page.dart';
import 'package:shared_preferences/shared_preferences.dart';
const _admin = UserEntity(
userId: 'admin-id',
username: 'Admin',
nickname: 'Admin',
token: 'admin-test',
orgId: 1,
roleKey: 'admin',
);
const _member = UserEntity(
userId: 'member-id',
username: 'Member',
nickname: 'Member',
token: 'member-test',
orgId: 1,
roleKey: 'manager',
);
class _VersionService extends Fake implements VersionCheckService {
final started = Completer<void>();
final result = Completer<AppVersionInfo?>();
int checks = 0;
@override
Future<AppVersionInfo?> checkUpdate({
required String currentVersion,
required int currentVersionCode,
}) {
checks++;
started.complete();
return result.future;
}
}
class _Strings extends LocalizationsDelegate<AppLocalizations> {
const _Strings(this.value);
final AppLocalizations value;
@override
bool isSupported(Locale locale) => true;
@override
Future<AppLocalizations> load(Locale locale) => SynchronousFuture(value);
@override
bool shouldReload(_Strings old) => false;
}
class _ProfileBundle extends CachingAssetBundle {
static final png = base64Decode(
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVR4nGNgAAIAAAUAAXpeqz8AAAAASUVORK5CYII=',
);
@override
Future<ByteData> load(String key) => key == 'assets/images/logo_me_bg.png'
? SynchronousFuture(ByteData.sublistView(png))
: rootBundle.load(key);
}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
test('non-admin tabs ignore the administrator configuration', () {
final config = TabConfig.defaultConfig()
.toggleItem('ai')
.toggleItem('device')
.toggleItem('work')
.toggleItem('me');
expect(config.navItemsForRole('admin').map((item) => item.id), ['ai']);
expect(config.settingItemsForRole('admin'), config.items);
for (final role in [null, 'personal', 'user', 'manager', 'siteManager']) {
final tabs = config.navItemsForRole(role);
expect(tabs.map((item) => item.id), ['device', 'work', 'me']);
expect(tabs.every((item) => item.isEnabled), isTrue);
expect(config.settingItemsForRole(role), tabs);
}
});
test(
'a pending administrator version check is discarded after switching users',
() async {
final users = AppUserCubit()..setAuth(_member);
final service = _VersionService();
final updates = UpdateCubit(service, users);
addTearDown(() async {
await updates.close();
await users.close();
});
await updates.checkUpdate();
expect(service.checks, 0);
expect(updates.state, isA<UpdateInitial>());
users.setAuth(_admin);
final check = updates.checkUpdate();
await service.started.future;
expect(updates.state, isA<UpdateChecking>());
users.setAuth(_member);
service.result.complete(null);
await check;
await Future<void>.delayed(Duration.zero);
expect(updates.state, isA<UpdateInitial>());
},
);
testWidgets(
'switching from admin locks tabs and hides float bar and updates',
(tester) async {
SharedPreferences.setMockInitialValues({});
final prefs = await SharedPreferences.getInstance();
final users = AppUserCubit()..setAuth(_admin);
final tabs = TabConfigCubit(prefs)
..toggleTab('device')
..toggleTab('work');
final locale = LocaleCubit(prefs);
final service = _VersionService();
final updates = UpdateCubit(service, users);
sl.registerSingleton(FloatBarSettingService(prefs));
addTearDown(() async {
await sl.unregister<FloatBarSettingService>();
await updates.close();
await locale.close();
await tabs.close();
await users.close();
});
final strings = (await tester.runAsync(() async {
final value = AppLocalizations(AppLocalizations.chinese);
expect(await value.load(), isTrue);
return value;
}))!;
final bundle = _ProfileBundle();
final navigator = GlobalKey<NavigatorState>();
await tester.pumpWidget(
MultiBlocProvider(
providers: [
BlocProvider<AppUserCubit>.value(value: users),
BlocProvider<TabConfigCubit>.value(value: tabs),
BlocProvider<LocaleCubit>.value(value: locale),
BlocProvider<UpdateCubit>.value(value: updates),
],
child: MaterialApp(
navigatorKey: navigator,
theme: AppTheme.lightTheme,
locale: AppLocalizations.chinese,
supportedLocales: AppLocalizations.supportedLocales,
localizationsDelegates: [
_Strings(strings),
...GlobalMaterialLocalizations.delegates,
],
builder: (_, child) =>
DefaultAssetBundle(bundle: bundle, child: child!),
home: const MainWrapper(),
),
),
);
await tester.pumpAndSettle();
expect(find.byType(MyPageV2), findsOneWidget);
expect(find.text('设备'), findsNothing);
navigator.currentState!.push<void>(
MaterialPageRoute(builder: (_) => const SystemSettingsPage()),
);
await tester.pumpAndSettle();
expect(find.text('AI'), findsOneWidget);
expect(
tester.widget<Switch>(find.byType(Switch).first).onChanged,
isNotNull,
);
final updatesTitle = find.text('版本更新');
await tester.scrollUntilVisible(
updatesTitle,
200,
scrollable: find.byType(Scrollable).first,
);
expect(updatesTitle, findsOneWidget);
users.setAuth(_member);
await FloatBarSettingService.setEnabled(true);
await tester.pumpAndSettle();
for (final label in ['设备', '作业', '我的']) {
expect(find.text(label), findsOneWidget);
}
for (final label in ['AI', '悬浮条', '版本更新']) {
expect(find.text(label), findsNothing);
}
final switches = tester.widgetList<Switch>(find.byType(Switch)).toList();
expect(switches, hasLength(3));
expect(
switches.every((toggle) => toggle.value && toggle.onChanged == null),
isTrue,
);
navigator.currentState!.pop();
await tester.pumpAndSettle();
expect(find.byType(MyPageV2), findsOneWidget);
expect(find.byType(FloatBarWidget), findsNothing);
for (final label in ['设备', '作业', '我的']) {
expect(find.text(label), findsOneWidget);
}
await tester.pumpWidget(const SizedBox.shrink());
},
);
}