@ -0,0 +1,563 @@
|
||||
import 'dart:io'; |
||||
|
||||
import 'package:flutter/material.dart'; |
||||
import 'package:flutter/services.dart'; |
||||
import 'package:flutter_test/flutter_test.dart'; |
||||
import 'package:integration_test/integration_test.dart'; |
||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; |
||||
import 'package:neon/l10n/localizations.dart'; |
||||
import 'package:neon/src/apps/files/app.dart'; |
||||
import 'package:neon/src/blocs/accounts.dart'; |
||||
import 'package:neon/src/blocs/capabilities.dart'; |
||||
import 'package:neon/src/blocs/push_notifications.dart'; |
||||
import 'package:neon/src/models/account.dart'; |
||||
import 'package:neon/src/neon.dart'; |
||||
import 'package:nextcloud/nextcloud.dart'; |
||||
import 'package:package_info_plus/package_info_plus.dart'; |
||||
import 'package:provider/provider.dart'; |
||||
import 'package:rxdart/rxdart.dart'; |
||||
import 'package:shared_preferences/shared_preferences.dart'; |
||||
|
||||
class MemorySharedPreferences implements SharedPreferences { |
||||
final _data = <String, dynamic>{}; |
||||
|
||||
@override |
||||
Future<bool> clear() async { |
||||
_data.clear(); |
||||
return true; |
||||
} |
||||
|
||||
@override |
||||
Future<bool> commit() async => true; |
||||
|
||||
@override |
||||
Future reload() async {} |
||||
|
||||
@override |
||||
Future<bool> remove(String key) async { |
||||
_data.remove(key); |
||||
return true; |
||||
} |
||||
|
||||
@override |
||||
Set<String> getKeys() => _data.keys.toSet(); |
||||
|
||||
@override |
||||
bool containsKey(String key) => _data.keys.contains(key); |
||||
|
||||
@override |
||||
Object? get(String key) => _data[key]; |
||||
|
||||
@override |
||||
bool? getBool(String key) => _data[key] as bool?; |
||||
|
||||
@override |
||||
double? getDouble(String key) => _data[key] as double?; |
||||
|
||||
@override |
||||
int? getInt(String key) => _data[key] as int?; |
||||
|
||||
@override |
||||
String? getString(String key) => _data[key] as String?; |
||||
|
||||
@override |
||||
List<String>? getStringList(String key) => (_data[key] as List).cast<String>(); |
||||
|
||||
@override |
||||
Future<bool> setBool(String key, bool value) async { |
||||
_data[key] = value; |
||||
return true; |
||||
} |
||||
|
||||
@override |
||||
Future<bool> setDouble(String key, double value) async { |
||||
_data[key] = value; |
||||
return true; |
||||
} |
||||
|
||||
@override |
||||
Future<bool> setInt(String key, int value) async { |
||||
_data[key] = value; |
||||
return true; |
||||
} |
||||
|
||||
@override |
||||
Future<bool> setString(String key, String value) async { |
||||
_data[key] = value; |
||||
return true; |
||||
} |
||||
|
||||
@override |
||||
Future<bool> setStringList(String key, List<String> value) async { |
||||
_data[key] = value; |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
Future pumpAppPage( |
||||
final WidgetTester tester, |
||||
final IntegrationTestWidgetsFlutterBinding binding, { |
||||
required final Widget Function(BuildContext, Function(NextcloudTheme)) builder, |
||||
final Account? account, |
||||
}) async { |
||||
final sharedPreferences = MemorySharedPreferences(); |
||||
|
||||
final platform = await getNeonPlatform(); |
||||
final requestManager = RequestManager(); |
||||
final allAppImplementations = getAppImplementations(sharedPreferences, requestManager, platform); |
||||
|
||||
final packageInfo = await PackageInfo.fromPlatform(); |
||||
|
||||
final globalOptions = GlobalOptions( |
||||
Storage('global', sharedPreferences), |
||||
packageInfo, |
||||
); |
||||
await globalOptions.pushNotificationsEnabled.set(false); |
||||
|
||||
final accountsBloc = AccountsBloc( |
||||
requestManager, |
||||
Storage('accounts', sharedPreferences), |
||||
sharedPreferences, |
||||
globalOptions, |
||||
packageInfo, |
||||
); |
||||
if (account != null) { |
||||
accountsBloc.addAccount(account..setupClient(packageInfo)); |
||||
} |
||||
|
||||
final pushNotificationsBloc = PushNotificationsBloc( |
||||
accountsBloc, |
||||
sharedPreferences, |
||||
globalOptions, |
||||
null, |
||||
platform, |
||||
); |
||||
|
||||
// ignore: close_sinks |
||||
final userThemeStream = BehaviorSubject<NextcloudTheme>(); |
||||
|
||||
await tester.pumpWidget( |
||||
MultiProvider( |
||||
providers: [ |
||||
Provider<SharedPreferences>( |
||||
create: (final _) => sharedPreferences, |
||||
), |
||||
Provider<Env?>( |
||||
create: (final _) => null, |
||||
), |
||||
Provider<NeonPlatform>( |
||||
create: (final _) => platform, |
||||
), |
||||
Provider<GlobalOptions>( |
||||
create: (final _) => globalOptions, |
||||
), |
||||
Provider<RequestManager>( |
||||
create: (final _) => requestManager, |
||||
), |
||||
Provider<AccountsBloc>( |
||||
create: (final _) => accountsBloc, |
||||
), |
||||
Provider<PushNotificationsBloc>( |
||||
create: (final _) => pushNotificationsBloc, |
||||
), |
||||
Provider<List<AppImplementation>>( |
||||
create: (final _) => allAppImplementations, |
||||
), |
||||
Provider<PackageInfo>( |
||||
create: (final _) => packageInfo, |
||||
), |
||||
], |
||||
child: StreamBuilder<NextcloudTheme>( |
||||
stream: userThemeStream, |
||||
builder: (final context, final themeSnapshot) => StreamBuilder<ThemeMode>( |
||||
stream: globalOptions.themeMode.stream, |
||||
builder: (final context, final themeModeSnapshot) => StreamBuilder<bool>( |
||||
stream: globalOptions.themeOLEDAsDark.stream, |
||||
builder: (final context, final themeOLEDAsDarkSnapshot) => MaterialApp( |
||||
debugShowCheckedModeBanner: false, |
||||
localizationsDelegates: AppLocalizations.localizationsDelegates, |
||||
supportedLocales: AppLocalizations.supportedLocales, |
||||
theme: getThemeFromNextcloudTheme( |
||||
themeSnapshot.data, |
||||
themeModeSnapshot.data ?? ThemeMode.system, |
||||
Brightness.light, |
||||
oledAsDark: themeOLEDAsDarkSnapshot.data ?? false, |
||||
), |
||||
home: builder(context, userThemeStream.add), |
||||
), |
||||
), |
||||
), |
||||
), |
||||
), |
||||
); |
||||
await tester.pumpAndSettle(); |
||||
} |
||||
|
||||
Future openDrawer(final WidgetTester tester) async { |
||||
await tester.tap(find.byTooltip('Open navigation menu')); |
||||
await tester.pumpAndSettle(); |
||||
} |
||||
|
||||
Future switchPage(final WidgetTester tester, final String name) async { |
||||
await openDrawer(tester); |
||||
await tester.tap(find.byKey(Key(name))); |
||||
await tester.pumpAndSettle(); |
||||
} |
||||
|
||||
Future prepareScreenshot(final WidgetTester tester, final IntegrationTestWidgetsFlutterBinding binding) async { |
||||
await binding.convertFlutterSurfaceToImage(); |
||||
await tester.pumpAndSettle(); |
||||
} |
||||
|
||||
Future main() async { |
||||
// The screenshots are pretty annoying on Android. See https://github.com/flutter/flutter/issues/92381 |
||||
|
||||
assert(Platform.isAndroid, 'Screenshots need to be taken on Android'); |
||||
|
||||
final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized(); |
||||
|
||||
final account = Account( |
||||
serverURL: 'http://10.0.2.2', |
||||
username: 'test', |
||||
password: 'supersafepasswordtocircumventpasswordpolicies', |
||||
); |
||||
|
||||
setUpAll(() async { |
||||
await SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); |
||||
}); |
||||
|
||||
testWidgets('login', (final tester) async { |
||||
await pumpAppPage( |
||||
tester, |
||||
binding, |
||||
builder: (final context, final _) => const LoginPage(), |
||||
); |
||||
await prepareScreenshot(tester, binding); |
||||
await binding.takeScreenshot('login_server_selection'); |
||||
|
||||
await tester.enterText(find.byType(TextFormField), account.serverURL); |
||||
await tester.pumpAndSettle(); |
||||
await tester.testTextInput.receiveAction(TextInputAction.done); |
||||
await tester.pumpAndSettle(); |
||||
await tester.pump(const Duration(seconds: 3)); // Make sure the login webview is loaded |
||||
await tester.pumpAndSettle(); |
||||
await binding.takeScreenshot('login_form'); |
||||
}); |
||||
|
||||
testWidgets('home', (final tester) async { |
||||
await pumpAppPage( |
||||
tester, |
||||
binding, |
||||
account: account, |
||||
builder: (final context, final onThemeChanged) => HomePage( |
||||
account: account, |
||||
onThemeChanged: onThemeChanged, |
||||
), |
||||
); |
||||
await openDrawer(tester); |
||||
await tester.pumpAndSettle(); |
||||
await tester.pump(); |
||||
await prepareScreenshot(tester, binding); |
||||
await binding.takeScreenshot('home_drawer'); |
||||
}); |
||||
|
||||
testWidgets('files', (final tester) async { |
||||
await pumpAppPage( |
||||
tester, |
||||
binding, |
||||
account: account, |
||||
builder: (final context, final onThemeChanged) => HomePage( |
||||
account: account, |
||||
onThemeChanged: onThemeChanged, |
||||
), |
||||
); |
||||
await prepareScreenshot(tester, binding); |
||||
await binding.takeScreenshot('files_root'); |
||||
|
||||
// Show Photos folder |
||||
await tester.tap(find.text('Photos')); |
||||
await tester.pumpAndSettle(); |
||||
|
||||
await binding.takeScreenshot('files_photos'); |
||||
|
||||
// Show file actions |
||||
await tester.tap(find.text('Photos')); |
||||
await tester.pumpAndSettle(); |
||||
await tester.tap(find.byType(PopupMenuButton<FilesFileAction>).first); |
||||
await tester.pumpAndSettle(); |
||||
|
||||
await binding.takeScreenshot('files_actions'); |
||||
|
||||
// Show details page |
||||
await tester.tap(find.text('Details')); |
||||
await tester.pumpAndSettle(); |
||||
|
||||
await binding.takeScreenshot('files_details'); |
||||
|
||||
// Show create dialog |
||||
await tester.tap(find.byIcon(Icons.arrow_back)); |
||||
await tester.pumpAndSettle(); |
||||
await tester.tap(find.byType(FloatingActionButton)); |
||||
await tester.pumpAndSettle(); |
||||
|
||||
await binding.takeScreenshot('files_create'); |
||||
}); |
||||
|
||||
testWidgets('news', (final tester) async { |
||||
const wikipediaFeedURL = 'https://en.wikipedia.org/w/api.php?action=featuredfeed&feed=featured&feedformat=atom'; |
||||
const nasaFeedURL = 'https://www.nasa.gov/rss/dyn/breaking_news.rss'; |
||||
|
||||
final folder = await account.client.news.createFolder( |
||||
NewsCreateFolder( |
||||
name: 'test', |
||||
), |
||||
); |
||||
await account.client.news.addFeed( |
||||
NewsAddFeed( |
||||
url: nasaFeedURL, |
||||
folderId: folder!.folders.single.id, |
||||
), |
||||
); |
||||
|
||||
await pumpAppPage( |
||||
tester, |
||||
binding, |
||||
account: account, |
||||
builder: (final context, final onThemeChanged) => HomePage( |
||||
account: account, |
||||
onThemeChanged: onThemeChanged, |
||||
), |
||||
); |
||||
await prepareScreenshot(tester, binding); |
||||
await switchPage(tester, 'app-news'); |
||||
|
||||
// Show folders |
||||
await tester.tap(find.byIcon(Icons.folder)); |
||||
await tester.pumpAndSettle(); |
||||
|
||||
await binding.takeScreenshot('news_folders_list'); |
||||
|
||||
// Add Wikipedia feed |
||||
await tester.tap(find.byIcon(Icons.rss_feed)); |
||||
await tester.pumpAndSettle(); |
||||
await tester.pump(); |
||||
await tester.tap(find.byType(FloatingActionButton)); |
||||
await tester.pumpAndSettle(); |
||||
|
||||
await binding.takeScreenshot('news_feed_add'); |
||||
|
||||
// Finish adding Wikipedia feed |
||||
await tester.enterText(find.byType(TextFormField), wikipediaFeedURL); |
||||
await tester.pumpAndSettle(); |
||||
await tester.tap(find.byType(ElevatedButton)); |
||||
await tester.pumpAndSettle(); |
||||
await tester.pump(const Duration(seconds: 3)); |
||||
await tester.pumpAndSettle(); |
||||
await tester.pump(); |
||||
|
||||
await binding.takeScreenshot('news_feeds_list'); |
||||
|
||||
// Open feed |
||||
await tester.tap(find.text('NASA Breaking News')); |
||||
await tester.pumpAndSettle(); |
||||
|
||||
await binding.takeScreenshot('news_feed_articles_list'); |
||||
|
||||
// Show unread articles |
||||
await tester.tap(find.byIcon(Icons.arrow_back)); |
||||
await tester.pumpAndSettle(); |
||||
await tester.tap(find.byIcon(Icons.newspaper)); |
||||
await tester.pumpAndSettle(); |
||||
|
||||
// Star two articles |
||||
await tester.tap(find.byIcon(Icons.star_outline).at(0)); |
||||
await tester.tap(find.byIcon(Icons.star_outline).at(1)); |
||||
await tester.pumpAndSettle(); |
||||
await tester.pump(const Duration(seconds: 3)); |
||||
|
||||
await binding.takeScreenshot('news_articles_unread_list'); |
||||
|
||||
// Show starred articles |
||||
await tester.tap(find.text('Unread')); |
||||
await tester.pumpAndSettle(); |
||||
await tester.tap(find.text('Starred').last); |
||||
await tester.pumpAndSettle(); |
||||
await tester.pump(const Duration(seconds: 3)); |
||||
|
||||
await binding.takeScreenshot('news_articles_starred_list'); |
||||
}); |
||||
|
||||
testWidgets('notes', (final tester) async { |
||||
await account.client.notes.createNote( |
||||
NotesNote( |
||||
title: 'Wishlist', |
||||
category: 'Financial', |
||||
), |
||||
); |
||||
|
||||
await pumpAppPage( |
||||
tester, |
||||
binding, |
||||
account: account, |
||||
builder: (final context, final onThemeChanged) => HomePage( |
||||
account: account, |
||||
onThemeChanged: onThemeChanged, |
||||
), |
||||
); |
||||
await prepareScreenshot(tester, binding); |
||||
await switchPage(tester, 'app-notes'); |
||||
|
||||
// Create note |
||||
await tester.tap(find.byType(FloatingActionButton)); |
||||
await tester.pumpAndSettle(); |
||||
await tester.enterText(find.byType(TextFormField).first, 'Grocery'); |
||||
await tester.pumpAndSettle(); |
||||
await tester.tap(find.byType(TextFormField).last); |
||||
await tester.pumpAndSettle(); |
||||
|
||||
await binding.takeScreenshot('notes_note_create'); |
||||
|
||||
// Finish creating note |
||||
await tester.enterText(find.byType(TextFormField).last, 'Financial'); |
||||
await tester.pumpAndSettle(); |
||||
await tester.testTextInput.receiveAction(TextInputAction.done); |
||||
await tester.pumpAndSettle(); |
||||
await tester.pump(const Duration(seconds: 3)); |
||||
|
||||
// Star note |
||||
await tester.tap(find.byIcon(Icons.star_outline).first); |
||||
await tester.pumpAndSettle(); |
||||
await tester.pump(const Duration(seconds: 3)); |
||||
|
||||
await binding.takeScreenshot('notes_notes_list'); |
||||
|
||||
// Edit note |
||||
await tester.tap(find.text('Grocery')); |
||||
await tester.pumpAndSettle(); |
||||
await tester.enterText(find.byType(TextField).first, '- Bread\n- Water\n- Apples'); |
||||
await tester.pumpAndSettle(); |
||||
await tester.pump(); // Needed for the text to actually show up |
||||
|
||||
await binding.takeScreenshot('notes_note_edit'); |
||||
|
||||
// Show note preview |
||||
await tester.tap(find.byIcon(Icons.visibility)); |
||||
await tester.pumpAndSettle(); |
||||
|
||||
await binding.takeScreenshot('notes_note_preview'); |
||||
|
||||
// Show categories |
||||
await tester.tap(find.byIcon(Icons.arrow_back)); |
||||
await tester.pumpAndSettle(); |
||||
await tester.tap(find.byIcon(MdiIcons.tag).last); |
||||
await tester.pumpAndSettle(); |
||||
|
||||
await binding.takeScreenshot('notes_categories_list'); |
||||
}); |
||||
|
||||
testWidgets('notifications', (final tester) async { |
||||
await account.client.notifications.sendAdminNotification( |
||||
account.username, |
||||
NotificationsAdminNotification( |
||||
shortMessage: 'Notifications demo', |
||||
longMessage: 'This is a notifications demo of the Neon app', |
||||
), |
||||
); |
||||
|
||||
await pumpAppPage( |
||||
tester, |
||||
binding, |
||||
account: account, |
||||
builder: (final context, final onThemeChanged) => HomePage( |
||||
account: account, |
||||
onThemeChanged: onThemeChanged, |
||||
), |
||||
); |
||||
await prepareScreenshot(tester, binding); |
||||
await switchPage(tester, 'app-notifications'); |
||||
|
||||
await tester.pumpAndSettle(); |
||||
await tester.pump(); |
||||
|
||||
await binding.takeScreenshot('notifications_list'); |
||||
}); |
||||
|
||||
testWidgets('settings', (final tester) async { |
||||
await pumpAppPage( |
||||
tester, |
||||
binding, |
||||
account: account, |
||||
builder: (final context, final onThemeChanged) => HomePage( |
||||
account: account, |
||||
onThemeChanged: onThemeChanged, |
||||
), |
||||
); |
||||
await prepareScreenshot(tester, binding); |
||||
await switchPage(tester, 'settings'); |
||||
|
||||
// Open Files settings |
||||
await tester.tap(find.text('Files')); |
||||
await tester.pumpAndSettle(); |
||||
|
||||
await binding.takeScreenshot('settings_app_files'); |
||||
|
||||
// Open News settings |
||||
await tester.tap(find.byIcon(Icons.arrow_back)); |
||||
await tester.pumpAndSettle(); |
||||
await tester.tap(find.text('News')); |
||||
await tester.pumpAndSettle(); |
||||
|
||||
await binding.takeScreenshot('settings_app_news'); |
||||
|
||||
// Open Notes settings |
||||
await tester.tap(find.byIcon(Icons.arrow_back)); |
||||
await tester.pumpAndSettle(); |
||||
await tester.tap(find.text('Notes')); |
||||
await tester.pumpAndSettle(); |
||||
|
||||
await binding.takeScreenshot('settings_app_notes'); |
||||
|
||||
// Go back to main page |
||||
await tester.tap(find.byIcon(Icons.arrow_back)); |
||||
await tester.pumpAndSettle(); |
||||
|
||||
await binding.takeScreenshot('settings_light'); |
||||
|
||||
// Change to dark theme |
||||
await tester.tap(find.text('Automatic')); |
||||
await tester.pumpAndSettle(); |
||||
await tester.tap(find.text('Dark').last); |
||||
await tester.pumpAndSettle(); |
||||
|
||||
await binding.takeScreenshot('settings_dark'); |
||||
|
||||
// Enable OLED theme |
||||
await tester.tap(find.byType(CheckboxListTile).first); |
||||
await tester.pumpAndSettle(); |
||||
|
||||
await binding.takeScreenshot('settings_oled'); |
||||
|
||||
// Change to back to light theme |
||||
await tester.tap(find.text('Dark')); |
||||
await tester.pumpAndSettle(); |
||||
await tester.tap(find.text('Light').last); |
||||
await tester.pumpAndSettle(); |
||||
|
||||
// Scroll down to accounts |
||||
await tester.drag(find.byType(ListView), const Offset(0, -10000)); |
||||
await tester.pumpAndSettle(); |
||||
|
||||
await binding.takeScreenshot('settings_accounts'); |
||||
|
||||
// Go to account settings |
||||
await tester.tap(find.byType(PopupMenuButton<SettingsAccountAction>)); |
||||
await tester.pumpAndSettle(); |
||||
await tester.tap(find.text('Settings').last); |
||||
await tester.pumpAndSettle(); |
||||
await tester.pump(); // Needed for the drop down button to actually show up |
||||
await tester.tap(find.text('Automatic')); |
||||
await tester.pumpAndSettle(); |
||||
|
||||
await binding.takeScreenshot('settings_account'); |
||||
}); |
||||
} |
After Width: | Height: | Size: 344 KiB |
Before Width: | Height: | Size: 254 KiB After Width: | Height: | Size: 274 KiB |
Before Width: | Height: | Size: 723 KiB After Width: | Height: | Size: 753 KiB |
Before Width: | Height: | Size: 312 KiB After Width: | Height: | Size: 324 KiB |
Before Width: | Height: | Size: 139 KiB After Width: | Height: | Size: 138 KiB |
After Width: | Height: | Size: 70 KiB |
Before Width: | Height: | Size: 918 KiB |
After Width: | Height: | Size: 971 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 155 KiB |
Before Width: | Height: | Size: 288 KiB |
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 101 KiB |
Before Width: | Height: | Size: 239 KiB After Width: | Height: | Size: 271 KiB |
After Width: | Height: | Size: 90 KiB |
After Width: | Height: | Size: 294 KiB |
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 95 KiB |
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 53 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 136 KiB |
Before Width: | Height: | Size: 105 KiB |
Before Width: | Height: | Size: 67 KiB |
After Width: | Height: | Size: 76 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 47 KiB |
After Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 153 KiB |
After Width: | Height: | Size: 80 KiB |
After Width: | Height: | Size: 152 KiB |
After Width: | Height: | Size: 113 KiB |
After Width: | Height: | Size: 139 KiB |
Before Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 140 KiB |
Before Width: | Height: | Size: 150 KiB |
Before Width: | Height: | Size: 112 KiB |
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 135 KiB |
@ -0,0 +1,23 @@
|
||||
import 'dart:io'; |
||||
|
||||
import 'package:integration_test/integration_test_driver_extended.dart'; |
||||
|
||||
Future<void> main() async { |
||||
final screenshotsDir = Directory('screenshots'); |
||||
if (screenshotsDir.existsSync()) { |
||||
screenshotsDir.deleteSync(recursive: true); |
||||
} |
||||
screenshotsDir.createSync(); |
||||
|
||||
try { |
||||
await integrationDriver( |
||||
onScreenshot: (final screenshotName, final screenshotBytes) async { |
||||
File('screenshots/$screenshotName.png').writeAsBytesSync(screenshotBytes); |
||||
return true; |
||||
}, |
||||
); |
||||
} catch (e) { |
||||
// ignore: avoid_print |
||||
print('Error occurred: $e'); |
||||
} |
||||
} |
@ -0,0 +1,5 @@
|
||||
#!/bin/bash |
||||
set -euxo pipefail |
||||
cd "$(dirname "$0")/.." |
||||
|
||||
docker build -t nextcloud-neon-dev --build-arg "username=$username" --build-arg "password=$password" -f - ./packages/nextcloud/test < tool/Dockerfile.dev |
@ -0,0 +1,5 @@
|
||||
#!/bin/bash |
||||
set -euxo pipefail |
||||
|
||||
export username="test" |
||||
export password="supersafepasswordtocircumventpasswordpolicies" |
@ -0,0 +1,20 @@
|
||||
#!/bin/bash |
||||
set -euxo pipefail |
||||
cd "$(dirname "$0")/.." |
||||
|
||||
source tool/common.sh |
||||
|
||||
./tool/build-dev-container-image.sh |
||||
container_id="$(docker run --rm -d -p "80:80" nextcloud-neon-dev)" |
||||
function cleanup() { |
||||
docker kill "$container_id" |
||||
} |
||||
trap cleanup EXIT |
||||
|
||||
( |
||||
cd packages/neon |
||||
fvm flutter drive \ |
||||
--driver=test_driver/integration_test.dart \ |
||||
--target=integration_test/screenshot_test.dart \ |
||||
--android-emulator |
||||
) |