Skip to content

Commit

Permalink
Add minimum integration test & Fix links in RowEditor and Remembet Me
Browse files Browse the repository at this point in the history
  • Loading branch information
enm10k committed Jun 21, 2024
1 parent 84af6d4 commit 2e09d14
Show file tree
Hide file tree
Showing 15 changed files with 169 additions and 48 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,5 @@ app.*.map.json
.fvm/flutter_sdk

_nocodb

integration_test/.env
11 changes: 6 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
fix:
dart fix --apply lib
run_integration_test rit:
flutter run --dart-define-from-file=integration_test/.env -t integration_test/hello_test.dart

fmt:
dart format lib
dart fix --apply lib
dart fix --apply integration_test
dart format lib integration_test

build-runner-watch watch:
# flutter pub run build_runner build -d -v
Expand All @@ -25,7 +27,6 @@ enable-db-log:
tail-db-log:
cd _nocodb/docker-compose/pg && docker-compose logs -f root_db


remove-generated-files:
find . | grep -e 'freezed\.dart' -e '\.g\.dart' | xargs -I {} rm {}

Expand All @@ -36,4 +37,4 @@ cloc:
cloc . --vcs=git --include-ext=dart,yaml lib

run-web:
CHROME_EXECUTABLE="./scripts/google-chrome-unsafe.sh" flutter run -d chrome
CHROME_EXECUTABLE="./scripts/google-chrome-unsafe.sh" flutter run -d chrome
8 changes: 8 additions & 0 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ android {
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName

// NOTE: To fix the following error.
//
// ERROR:D8: Cannot fit requested classes in a single dex file (# methods: 81117 > 65536)
// com.android.builder.dexing.DexArchiveMergerException: Error while merging dex archives:
// The number of method references in a .dex file cannot exceed 64K.
// Learn how to resolve this issue at https://developer.android.com/tools/building/multidex.html
multiDexEnabled true
}

buildTypes {
Expand Down
63 changes: 63 additions & 0 deletions integration_test/hello_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import 'dart:io';

import 'package:flutter/cupertino.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:nocodb/main.dart';

const NC_ENDPOINT = String.fromEnvironment('NC_ENDPOINT');
const NC_USER = String.fromEnvironment('NC_USER');
const NC_PASS = String.fromEnvironment('NC_PASS');

// https://github.com/flutter/flutter/issues/88765#issuecomment-1113140289
Future<void> waitFor(
final WidgetTester tester,
final Finder finder, {
final Duration timeout = const Duration(seconds: 20),
}) async {
final end = DateTime.now().add(timeout);

do {
if (DateTime.now().isAfter(end)) {
throw Exception('Timed out waiting for $finder');
}

await tester.pumpAndSettle();
await Future.delayed(const Duration(milliseconds: 100));
} while (finder.evaluate().isEmpty);
}

void main() {
HttpOverrides.global = null;
IntegrationTestWidgetsFlutterBinding.ensureInitialized();

testWidgets('sign in', (final WidgetTester tester) async {
await tester.pumpWidget(
const ProviderScope(
child: App(),
),
);
await waitFor(tester, find.text('SIGN IN'));

await tester.enterText(
find.byKey(const ValueKey('email')),
NC_USER,
);
await tester.enterText(
find.byKey(const ValueKey('password')),
NC_PASS,
);
await tester.enterText(
find.byKey(const ValueKey('endpoint')),
NC_ENDPOINT,
);
await tester.tap(
find.byKey(const ValueKey('sign_in_button')),
);

await tester.pumpAndSettle();

await waitFor(tester, find.text('Projects'));
});
}
4 changes: 1 addition & 3 deletions lib/features/core/components/dialog/fields_dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,7 @@ class FieldsDialog extends HookConsumerWidget {
),
InkWell(
onTap: () {
ref
.read(viewProvider.notifier)
.showSystemFields();
ref.read(viewProvider.notifier).showSystemFields();
},
child: Row(
children: [
Expand Down
1 change: 1 addition & 0 deletions lib/features/core/components/editor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ class Editor extends HookConsumerWidget {
maxLines: null,
keyboardType: TextInputType.multiline,
);
case UITypes.links:
case UITypes.linkToAnotherRecord:
final tables = ref.watch(tablesProvider);
final relation = tables?.relationMap[column.fkRelatedModelId];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class LinkToAnotherRecord extends HookConsumerWidget {
return [
...records.map<Widget>((final record) {
final (pk, pv) = record;
return _buildCard(value: pv, refRowId: pk, ref: ref);
return _buildCard(value: pv.toString(), refRowId: pk, ref: ref);
}),
if (9 < records.length)
Card(
Expand Down
3 changes: 2 additions & 1 deletion lib/features/core/providers/providers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ class View extends _$View {
data: {
'show_system_fields': !state!.showSystemFields,
},
), serializer: (final ok) => state = ok,
),
serializer: (final ok) => state = ok,
);
}

Expand Down
9 changes: 7 additions & 2 deletions lib/features/sign_in/pages/sign_in.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class SignInPage extends HookConsumerWidget {
child: Column(
children: [
TextField(
key: const ValueKey('email'),
autofillHints: const [
AutofillHints.email,
AutofillHints.username,
Expand All @@ -72,6 +73,7 @@ class SignInPage extends HookConsumerWidget {
),
),
TextField(
key: const ValueKey('password'),
autofillHints: const [
AutofillHints.password,
],
Expand All @@ -92,9 +94,10 @@ class SignInPage extends HookConsumerWidget {
obscureText: !showPassword.value,
),
TextField(
key: const ValueKey('endpoint'),
onChanged: (final value) {
EasyDebounce.debounce(
'sign_in_password',
'api_endpoint',
const Duration(seconds: 1),
() async {
await api
Expand Down Expand Up @@ -138,6 +141,7 @@ class SignInPage extends HookConsumerWidget {
),
actions: [
TextButton(
key: const ValueKey('sign_in_button'),
child: const Text('SIGN IN'),
onPressed: () async {
api.init(apiUrlController.text);
Expand All @@ -147,14 +151,15 @@ class SignInPage extends HookConsumerWidget {
passwordController.text,
)
.then((final authToken) async {
// TODO: Need to rewrite Settings class. The following values should not be saved to the storage when rememberMe is false.
await settings.setApiBaseUrl(apiUrlController.text);
await authToken.when(
ok: (final token) async {
if (rememberMe.value) {
await settings.setEmail(emailController.text);
await settings.setRememberMe(rememberMe.value);
await settings.setAuthToken(token);
} else {
await settings.clear();
}
if (context.mounted) {
const ProjectListRoute().go(context);
Expand Down
1 change: 0 additions & 1 deletion lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ void main() async {
return stack;
};

// WidgetsFlutterBinding.ensureInitialized();
runApp(
const ProviderScope(
child: App(),
Expand Down
18 changes: 7 additions & 11 deletions lib/nocodb_sdk/client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ class _Api {

init(final String url, {final String? authToken}) {
_baseUri = Uri.parse(url);
logger.info(_baseUri);
if (authToken != null) {
_client.addHeaders({'xc-auth': authToken});
} else {
Expand Down Expand Up @@ -243,16 +242,13 @@ class _Api {
},
);

// Future<Result<model.NcUser>> me(
// [final Map<String, dynamic>? queryParameters]) async =>
// await _send2(
// method: HttpMethod.get,
// path: '/api/v1/auth/user/me',
// serializer: (final _, final data) {
// final user = model.NcUser.fromJson(data);
// return Result.ok(user);
// },
// );
Future<Result<model.NcUser>> authUserMe(
[final Map<String, dynamic>? queryParameters]) async =>
await _send(
method: HttpMethod.get,
path: '/api/v1/auth/user/me',
serializer: (final _, final data) => model.NcUser.fromJson(data),
);

Future<model.Result<model.NcList<model.NcProject>>> projectList() async =>
await _send(
Expand Down
45 changes: 23 additions & 22 deletions lib/router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:nocodb/common/preferences.dart';
import 'package:nocodb/common/settings.dart';
import 'package:nocodb/nocodb_sdk/client.dart';
import 'package:nocodb/routes.dart';
import 'package:path/path.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'router.g.dart';
Expand All @@ -21,8 +22,8 @@ part 'router.g.dart';
final rawHeader = parts[0];
final rawPayload = parts[1];

final header = String.fromCharCodes(base64Decode(rawHeader));
final payload = String.fromCharCodes(base64Decode(rawPayload));
final header = String.fromCharCodes(base64Decode(base64.normalize(rawHeader)));
final payload = String.fromCharCodes(base64Decode(base64.normalize(rawPayload)));
return (jsonDecode(header), jsonDecode(payload));
}

Expand Down Expand Up @@ -62,14 +63,17 @@ FutureOr<String?> redirect(
}

final rememberMe = await settings.rememberMe;
if (!rememberMe) {
return null;
}

final apiBaseUrl = await settings.apiBaseUrl;
final authToken = await settings.authToken;

logger.config('apiBaseUrl: $apiBaseUrl');

if (authToken == null || apiBaseUrl == null) {
return const HomeRoute().location;
} else if (state.path == const HomeRoute().location) {
} else if (state.path == null || state.path == const HomeRoute().location) {
if (!rememberMe) {
await settings.clear();
return const HomeRoute().location;
Expand All @@ -81,24 +85,22 @@ FutureOr<String?> redirect(
);

if (isAlive) {
final result = await api.version(apiBaseUrl);
result.when(
ok: (final ok) {
if (!ok) {
if (!ok) {
return const HomeRoute().location;
}
api.init(apiBaseUrl, authToken: authToken);
return const ProjectListRoute().location;
}
},
ng: (final error, final stackTrace) =>
notifyError(context, error, stackTrace),
);
api.init(apiBaseUrl, authToken: authToken);
return const ProjectListRoute().location;
// final result = await api.authUserMe();
// return result.when(
// ok: (final ok) {
// api.init(apiBaseUrl, authToken: authToken);
// return const ProjectListRoute().location;
// },
// ng: (final error, final stackTrace) =>
// notifyError(context, error, stackTrace),
// );
}
}
} catch (e) {
logger.warning(e);
} catch (e, s) {
logger..warning(e)
..warning(s);
return const HomeRoute().location;
}

Expand All @@ -110,9 +112,8 @@ GoRouter router(final RouterRef ref) => GoRouter(
routes: $appRoutes,
debugLogDiagnostics: true,
redirect: (final context, final state) async {
logger.info('redirecting ...');
final location = await redirect(context, state);
if (location == null) {
if (location != null) {
logger.info('redirected to $location');
}
return location;
Expand Down
Loading

0 comments on commit 2e09d14

Please sign in to comment.