Integrate themed login/signup, EN/RU localization, shared dummy providers, verification recovery screens and named URL routes. Store frontend guidelines, workflow skills, validation and delivery documentation. Related to #2, #3, #5 and #6.
139 lines
5.0 KiB
Dart
139 lines
5.0 KiB
Dart
import 'dart:convert';
|
|
import 'dart:io';
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
|
|
import 'package:sxchnge_app/main.dart';
|
|
import 'package:sxchnge_app/providers/locale.dart';
|
|
|
|
void main() {
|
|
TestWidgetsFlutterBinding.ensureInitialized();
|
|
|
|
setUp(() => SharedPreferences.setMockInitialValues({}));
|
|
|
|
test('saved choice overrides system locale, with English fallback', () async {
|
|
expect(
|
|
LocaleProvider.resolve(null, [const Locale('ru', 'RU')]),
|
|
const Locale('ru'),
|
|
);
|
|
expect(
|
|
LocaleProvider.resolve('en', [const Locale('ru')]),
|
|
const Locale('en'),
|
|
);
|
|
expect(
|
|
LocaleProvider.resolve('ru-RU', [const Locale('en')]),
|
|
const Locale('ru'),
|
|
);
|
|
expect(
|
|
LocaleProvider.resolve('de', [const Locale('ru')]),
|
|
const Locale('en'),
|
|
);
|
|
expect(
|
|
LocaleProvider.resolve(null, [const Locale('fr')]),
|
|
const Locale('en'),
|
|
);
|
|
expect(LocaleProvider.resolve(null, []), const Locale('en'));
|
|
final first = await LocaleProvider.load([const Locale('en')]);
|
|
await first.setLocale(const Locale('ru'));
|
|
final restarted = await LocaleProvider.load([const Locale('en')]);
|
|
expect(restarted.locale, const Locale('ru'));
|
|
await Future.wait([
|
|
first.setLocale(const Locale('en')),
|
|
first.setLocale(const Locale('ru')),
|
|
]);
|
|
expect(
|
|
(await SharedPreferences.getInstance()).getString(
|
|
LocaleProvider.storageKey,
|
|
),
|
|
'ru',
|
|
);
|
|
first.dispose();
|
|
restarted.dispose();
|
|
});
|
|
|
|
test('catalogs have equal keys and no empty translations', () {
|
|
final en = jsonDecode(File('lib/l10n/en.arb').readAsStringSync()) as Map;
|
|
final ru = jsonDecode(File('lib/l10n/ru.arb').readAsStringSync()) as Map;
|
|
expect(ru.keys.toSet(), en.keys.toSet());
|
|
expect(
|
|
ru.values.every((value) => value is String && value.trim().isNotEmpty),
|
|
isTrue,
|
|
);
|
|
});
|
|
|
|
testWidgets(
|
|
'switching language updates errors and keeps form data and mode',
|
|
(tester) async {
|
|
tester.view.physicalSize = const Size(1440, 1200);
|
|
tester.view.devicePixelRatio = 1;
|
|
addTearDown(tester.view.resetPhysicalSize);
|
|
addTearDown(tester.view.resetDevicePixelRatio);
|
|
final locale = await LocaleProvider.load([const Locale('en')]);
|
|
await tester.pumpWidget(SxchngeApp(localeProvider: locale));
|
|
await tester.pumpAndSettle();
|
|
await tester.tap(find.text('Sign up'));
|
|
await tester.pumpAndSettle();
|
|
await tester.enterText(find.byKey(const ValueKey('name')), 'Алексей');
|
|
await tester.enterText(find.byKey(const ValueKey('email')), 'invalid');
|
|
await tester.ensureVisible(find.byKey(const ValueKey('submit')));
|
|
await tester.tap(find.byKey(const ValueKey('submit')));
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('Enter a valid email address.'), findsOneWidget);
|
|
await tester.ensureVisible(find.byKey(const ValueKey('locale-selector')));
|
|
await tester.tap(find.byKey(const ValueKey('locale-selector')));
|
|
await tester.pumpAndSettle();
|
|
await tester.tap(
|
|
find.ancestor(
|
|
of: find.text('Русский'),
|
|
matching: find.byType(CheckedPopupMenuItem<Locale>),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('Введите корректный адрес почты.'), findsOneWidget);
|
|
expect(find.text('Алексей'), findsOneWidget);
|
|
expect(find.text('invalid'), findsOneWidget);
|
|
expect(find.byKey(const ValueKey('confirmation')), findsOneWidget);
|
|
expect(find.byTooltip('Показать пароль'), findsOneWidget);
|
|
expect(
|
|
(await SharedPreferences.getInstance()).getString(
|
|
LocaleProvider.storageKey,
|
|
),
|
|
'ru',
|
|
);
|
|
expect(tester.takeException(), isNull);
|
|
},
|
|
);
|
|
|
|
for (final width in [320.0, 1440.0]) {
|
|
testWidgets('Russian forms fit at width $width with 200% text', (
|
|
tester,
|
|
) async {
|
|
tester.view.physicalSize = Size(width, 1000);
|
|
tester.view.devicePixelRatio = 1;
|
|
tester.platformDispatcher.textScaleFactorTestValue = 2;
|
|
addTearDown(tester.view.resetPhysicalSize);
|
|
addTearDown(tester.view.resetDevicePixelRatio);
|
|
addTearDown(tester.platformDispatcher.clearTextScaleFactorTestValue);
|
|
await tester.pumpWidget(
|
|
SxchngeApp(
|
|
localeProvider: LocaleProvider(initialLocale: const Locale('ru')),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(tester.takeException(), isNull);
|
|
await tester.ensureVisible(find.text('Регистрация'));
|
|
await tester.tap(find.text('Регистрация'));
|
|
await tester.pumpAndSettle();
|
|
await tester.ensureVisible(find.byKey(const ValueKey('submit')));
|
|
await tester.tap(find.byKey(const ValueKey('submit')));
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('Введите ваше имя.'), findsOneWidget);
|
|
expect(tester.takeException(), isNull);
|
|
});
|
|
}
|
|
}
|