chore: add initial golden tests
No files matched your search
@@ -55,6 +55,17 @@ jobs:
|
||||
- name: Add Firebase Messaging
|
||||
run: ./scripts/add-firebase-messaging.sh
|
||||
- run: flutter analyze
|
||||
|
||||
flutter_tests:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: subosito/flutter-action@v2
|
||||
with:
|
||||
flutter-version-file: .tool_versions.yaml
|
||||
cache: true
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- run: flutter pub get
|
||||
- run: flutter test
|
||||
|
||||
build_debug_apk:
|
||||
|
||||
@@ -203,3 +203,5 @@ ios/Runner/GoogleServices-Info.plist
|
||||
web/e2ee.worker.dart.js
|
||||
web/e2ee.worker.dart.js.deps
|
||||
web/e2ee.worker.dart.js.map
|
||||
|
||||
test/rust
|
||||
@@ -26,7 +26,7 @@ To improve the process please make sure that you read the following guidelines c
|
||||
12. Do not fire&forget a pull request! Contributing also means taking over responsibility, reacting on comments and reviews and be able to collaborate.
|
||||
13. Do not overengineer something. Not everything needs to be abstracted, if it isn't used in more than one place. Code must fit in the current architecture.
|
||||
14. Avoid using `else` and prefer function guards, early returns and `switch`.
|
||||
15. Do not add functionality in the platform-directories. We try to not differ from the default as these creates huge conflicts on upgrading Flutter versions. We do not have our own platform channels but abstracted them in external packages. We must try to get rid of existing workarounds and not extend them!
|
||||
15. Do not add functionality in the platform-directories. We try to not differ from the default as these creates huge conflicts on upgrading Flutter versions. We do not have our own platform channels but abstracted them in external packages. We must try to get rid of existing workarounds and not extend them! Exceptions are for edge cases like the Notification Service Extension on iOS.
|
||||
16. Keep all dependencies and external packages minimal. Make sure that new packages are well maintained and no threat to future dependency hell.
|
||||
|
||||
# Code Style
|
||||
|
||||
@@ -26,7 +26,8 @@ path = [
|
||||
"integration_test/synapse/**",
|
||||
"snap/**",
|
||||
"windows/**",
|
||||
"web/**"
|
||||
"web/**",
|
||||
"test/metadata/**"
|
||||
]
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2019-Present Christian Kußowski"
|
||||
@@ -56,7 +57,7 @@ path = [
|
||||
"web/icons/**",
|
||||
"web/splash/**",
|
||||
"snap/gui/*.png",
|
||||
"windows/runner/resources/app_icon.ico"
|
||||
"windows/runner/resources/app_icon.ico",
|
||||
]
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2017-Present Fabiyamada"
|
||||
|
||||
@@ -27,6 +27,7 @@ class FluffyChatApp extends StatelessWidget {
|
||||
final List<Client> clients;
|
||||
final ({String? pincode, bool useBiometrics}) appLockSettings;
|
||||
final SharedPreferences store;
|
||||
final Locale? locale;
|
||||
|
||||
const FluffyChatApp({
|
||||
super.key,
|
||||
@@ -34,6 +35,7 @@ class FluffyChatApp extends StatelessWidget {
|
||||
required this.clients,
|
||||
required this.store,
|
||||
required this.appLockSettings,
|
||||
this.locale,
|
||||
});
|
||||
|
||||
/// getInitialLink may rereturn the value multiple times if this view is
|
||||
@@ -87,6 +89,8 @@ class FluffyChatApp extends StatelessWidget {
|
||||
builder: (context, themeMode, primaryColor) => MaterialApp.router(
|
||||
title: AppSettings.applicationName.value,
|
||||
themeMode: themeMode,
|
||||
debugShowCheckedModeBanner: false,
|
||||
locale: locale,
|
||||
theme: FluffyThemes.buildTheme(context, Brightness.light, primaryColor),
|
||||
darkTheme: FluffyThemes.buildTheme(
|
||||
context,
|
||||
|
||||
@@ -289,6 +289,8 @@ class MatrixState extends State<Matrix> {
|
||||
),
|
||||
windows: ClientManager.windowsNotificationSettings,
|
||||
macOS: const DarwinInitializationSettings(),
|
||||
iOS: const DarwinInitializationSettings(),
|
||||
android: const AndroidInitializationSettings('notifications_icon'),
|
||||
),
|
||||
onDidReceiveNotificationResponse: (response) => notificationTap(
|
||||
response,
|
||||
|
||||
@@ -879,6 +879,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "18.0.2"
|
||||
golden_screenshot:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: golden_screenshot
|
||||
sha256: f1e894eb4d4f8c87a65b7d43ee95d84733f9e1e7980e3e0be5c3165b8b030792
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "12.1.1"
|
||||
gsettings:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2338,7 +2346,7 @@ packages:
|
||||
source: hosted
|
||||
version: "15.2.0"
|
||||
vodozemac:
|
||||
dependency: transitive
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: vodozemac
|
||||
sha256: efce261575f7de97ebd052b16775cd57f940e8212af47d288050c166b9f9a167
|
||||
|
||||
@@ -102,9 +102,11 @@ dev_dependencies:
|
||||
flutter_lints: ^6.0.0
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
golden_screenshot: ^12.1.1
|
||||
integration_test:
|
||||
sdk: flutter
|
||||
license_checker: ^1.6.2
|
||||
vodozemac: ^0.8.0
|
||||
|
||||
flutter:
|
||||
generate: true
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# SPDX-FileCopyrightText: 2019-Present Christian Kußowski
|
||||
# SPDX-FileCopyrightText: 2019-Present Contributors to FluffyChat
|
||||
#
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
set -e
|
||||
version=$(yq ".packages.vodozemac.version" < pubspec.lock)
|
||||
rm -rf ./test/rust dart-vodozemac
|
||||
git clone https://github.com/famedly/dart-vodozemac.git -b "$version"
|
||||
mv ./dart-vodozemac/rust ./test/
|
||||
rm -rf dart-vodozemac
|
||||
cd ./test/rust && cargo build && cd ../..
|
||||
@@ -23,6 +23,7 @@ find . -type f \
|
||||
-not -path "*/snap/*" \
|
||||
-not -path "*/web/*" \
|
||||
-not -path "*/windows/*" \
|
||||
-not -path "*/test/metadata/*" \
|
||||
-exec reuse annotate \
|
||||
--copyright="Christian Kußowski" \
|
||||
--copyright="Contributors to FluffyChat" \
|
||||
|
||||
@@ -7,8 +7,8 @@ import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'utils/test_client.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
|
||||
|
||||
void main() async {
|
||||
test('Check for missing /command hints', () async {
|
||||
@@ -16,7 +16,14 @@ void main() async {
|
||||
jsonDecode(File('lib/l10n/intl_en.arb').readAsStringSync()).keys
|
||||
.where((String k) => k.startsWith('commandHint_'))
|
||||
.map((k) => k.replaceFirst('commandHint_', ''));
|
||||
final commands = (await prepareTestClient()).commands.keys;
|
||||
final commands = (Client(
|
||||
'commands',
|
||||
database: await MatrixSdkDatabase.init(
|
||||
'test',
|
||||
database: await databaseFactoryFfi.openDatabase(':memory:'),
|
||||
sqfliteFactory: databaseFactoryFfi,
|
||||
),
|
||||
)).commands.keys;
|
||||
final missing = commands.where((c) => !translated.contains(c)).toList();
|
||||
|
||||
expect(
|
||||
|
||||
|
After Width: | Height: | Size: 58 KiB |
|
After Width: | Height: | Size: 57 KiB |
|
After Width: | Height: | Size: 133 KiB |
|
After Width: | Height: | Size: 133 KiB |
|
After Width: | Height: | Size: 149 KiB |
|
After Width: | Height: | Size: 150 KiB |
|
After Width: | Height: | Size: 125 KiB |
|
After Width: | Height: | Size: 122 KiB |
|
After Width: | Height: | Size: 148 KiB |
|
After Width: | Height: | Size: 148 KiB |
|
After Width: | Height: | Size: 96 KiB |
|
After Width: | Height: | Size: 96 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 130 KiB |
|
After Width: | Height: | Size: 131 KiB |
|
After Width: | Height: | Size: 143 KiB |
|
After Width: | Height: | Size: 145 KiB |
|
After Width: | Height: | Size: 124 KiB |
|
After Width: | Height: | Size: 121 KiB |
|
After Width: | Height: | Size: 142 KiB |
|
After Width: | Height: | Size: 143 KiB |
|
After Width: | Height: | Size: 95 KiB |
|
After Width: | Height: | Size: 95 KiB |
@@ -0,0 +1,62 @@
|
||||
// SPDX-FileCopyrightText: 2019-Present Christian Kußowski
|
||||
// SPDX-FileCopyrightText: 2019-Present Contributors to FluffyChat
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import 'package:fluffychat/config/setting_keys.dart';
|
||||
import 'package:fluffychat/widgets/fluffy_chat_app.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:golden_screenshot/golden_screenshot.dart';
|
||||
import 'package:material_ui/material_ui.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../utils/golden_locales.dart';
|
||||
import '../utils/test_client.dart';
|
||||
|
||||
void main() {
|
||||
group('ChatList Golden', () {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
late Client client;
|
||||
|
||||
setUpAll(() async {
|
||||
client = await prepareTestClient();
|
||||
client.backgroundSync = false;
|
||||
});
|
||||
testGoldens('ChatList Screenshot', (tester) async {
|
||||
for (final locale in goldenLocals) {
|
||||
for (final device in GoldenScreenshotDevices.values) {
|
||||
for (final themeMode in {ThemeMode.dark, ThemeMode.light}) {
|
||||
client.userDeviceKeys.clear(); // Hide unverified warning
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setString('theme_mode', themeMode.name);
|
||||
await tester.pumpWidget(
|
||||
ScreenshotApp.withConditionalTitlebar(
|
||||
title: AppSettings.applicationName.value,
|
||||
device: device.device,
|
||||
home: FluffyChatApp(
|
||||
clients: [client],
|
||||
store: prefs,
|
||||
appLockSettings: (pincode: null, useBiometrics: false),
|
||||
locale: locale,
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pump(const Duration(milliseconds: 100));
|
||||
|
||||
await tester.loadAssets();
|
||||
await tester.pump(const Duration(milliseconds: 100));
|
||||
await tester.expectScreenshot(
|
||||
device.device,
|
||||
'${themeMode.name}_chat_list_page',
|
||||
finder: find.byType(MaterialApp).first,
|
||||
langCode: locale.languageCode,
|
||||
);
|
||||
await tester.pumpWidget(const SizedBox());
|
||||
await tester.pump(const Duration(milliseconds: 100));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// SPDX-FileCopyrightText: 2019-Present Christian Kußowski
|
||||
// SPDX-FileCopyrightText: 2019-Present Contributors to FluffyChat
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
const goldenLocals = [Locale('en'), Locale('de')];
|
||||
@@ -0,0 +1,17 @@
|
||||
// SPDX-FileCopyrightText: 2019-Present Christian Kußowski
|
||||
// SPDX-FileCopyrightText: 2019-Present Contributors to FluffyChat
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
// ignore: depend_on_referenced_packages
|
||||
import 'package:vodozemac/vodozemac.dart' as vod;
|
||||
|
||||
Future<void> setUpVodozemac() async {
|
||||
if (vod.isInitialized()) return;
|
||||
if (!await Directory('./test/rust').exists()) {
|
||||
await Process.run('./scripts/prepare_vodozemac.sh', []);
|
||||
}
|
||||
await vod.init(wasmPath: './pkg/', libraryPath: 'test/rust/target/debug/');
|
||||
}
|
||||
@@ -5,20 +5,35 @@
|
||||
|
||||
// ignore_for_file: depend_on_referenced_packages
|
||||
|
||||
import 'package:fluffychat/config/setting_keys.dart';
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
import 'package:matrix/encryption/utils/key_verification.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
|
||||
|
||||
import 'set_up_vodozemac.dart';
|
||||
|
||||
// key @test:fakeServer.notExisting
|
||||
const pickledOlmAccount =
|
||||
'huxcPifHlyiQsX7cZeMMITbka3hLeUT3ss6DLL6dV7knaD4wgAYK6gcWknkixnX8C5KMIyxzytxiNqAOhDFRE5NsET8hr2dQ8OvXX7M95eQ7/3dPi7FkPUIbvneTSGgJYNDxJdHsDJ8OBHZ3BoqUJFDbTzFfVJjEzN4G9XQwPDafZ2p5WyerOK8Twj/rvk5N+ERmkt1XgVLQl66we/BO1ugTeM3YpDHm5lTzFUitJGTIuuONsKG9mmzdAmVUJ9YIrSxwmOBdegbGA+LAl5acg5VOol3KxRgZUMJQRQ58zpBAs72oauHizv1QVoQ7uIUiCUeb9lym+TEjmApvhru/1CPHU90K5jHNZ57wb/4V9VsqBWuoNibzDWG35YTFLcx0o+1lrCIjm1QjuC0777G+L1HNw5wnppV3z/k0YujjuPS3wvOA30TjHg';
|
||||
|
||||
class _FakeNotifications extends FlutterLocalNotificationsPlatform {}
|
||||
|
||||
Future<Client> prepareTestClient({
|
||||
bool loggedIn = false,
|
||||
Uri? homeserver,
|
||||
String id = 'FluffyChat Widget Test',
|
||||
}) async {
|
||||
await setUpVodozemac();
|
||||
SharedPreferences.setMockInitialValues({});
|
||||
FlutterLocalNotificationsPlatform.instance = _FakeNotifications();
|
||||
await AppSettings.init(loadWebConfigFile: false);
|
||||
|
||||
homeserver ??= Uri.parse('https://fakeserver.notexisting');
|
||||
final client = Client(
|
||||
'FluffyChat Widget Tests',
|
||||
httpClient: FakeMatrixApi()
|
||||
..api['GET']!['/.well-known/matrix/client'] = (req) => {},
|
||||
httpClient: FakeMatrixApi(),
|
||||
verificationMethods: {
|
||||
KeyVerificationMethod.numbers,
|
||||
KeyVerificationMethod.emoji,
|
||||
@@ -36,13 +51,13 @@ Future<Client> prepareTestClient({
|
||||
AuthenticationTypes.sso,
|
||||
},
|
||||
);
|
||||
await client.checkHomeserver(homeserver);
|
||||
if (loggedIn) {
|
||||
await client.login(
|
||||
LoginType.mLoginToken,
|
||||
identifier: AuthenticationUserIdentifier(user: '@alice:example.invalid'),
|
||||
password: '1234',
|
||||
);
|
||||
}
|
||||
await client.init(
|
||||
newHomeserver: Uri.parse('https://fakeServer.notExisting'),
|
||||
newDeviceID: 'ABCD1234',
|
||||
newDeviceName: 'Screenshot Tester',
|
||||
newToken: '1234',
|
||||
newUserID: '@test:fakeServer.notExisting',
|
||||
newOlmAccount: pickledOlmAccount,
|
||||
);
|
||||
return client;
|
||||
}
|
||||