mirror of
https://github.com/Xevion/paperless-mobile.git
synced 2025-12-06 01:15:44 -06:00
feat: Add tests, update notes implementation
This commit is contained in:
@@ -9,4 +9,9 @@ class InfoMessageException implements Exception {
|
||||
this.message,
|
||||
this.stackTrace,
|
||||
});
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'InfoMessageException(code: $code, message: $message, stackTrace: $stackTrace)';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import 'dart:io';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:dio/io.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:paperless_mobile/core/interceptor/dio_http_error_interceptor.dart';
|
||||
import 'package:paperless_api/src/interceptor/dio_http_error_interceptor.dart';
|
||||
import 'package:paperless_mobile/core/interceptor/dio_offline_interceptor.dart';
|
||||
import 'package:paperless_mobile/core/interceptor/dio_unauthorized_interceptor.dart';
|
||||
import 'package:paperless_mobile/core/interceptor/retry_on_connection_change_interceptor.dart';
|
||||
|
||||
@@ -82,5 +82,7 @@ String translateError(BuildContext context, ErrorCode code) {
|
||||
'Could not load custom field.', //TODO: INTL
|
||||
ErrorCode.customFieldDeleteFailed =>
|
||||
'Could not delete custom field, please try again.', //TODO: INTL
|
||||
ErrorCode.deleteNoteFailed => 'Could not delete note, please try again.',
|
||||
ErrorCode.addNoteFailed => 'Could not create note, please try again.',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -311,4 +311,17 @@ class DocumentDetailsCubit extends Cubit<DocumentDetailsState> {
|
||||
_notifier.removeListener(this);
|
||||
await super.close();
|
||||
}
|
||||
|
||||
Future<void> addNote(String text) async {
|
||||
assert(state.status == LoadingStatus.loaded);
|
||||
try {
|
||||
final updatedDocument = await _api.addNote(
|
||||
document: state.document!,
|
||||
text: text,
|
||||
);
|
||||
_notifier.notifyUpdated(updatedDocument);
|
||||
} on PaperlessApiException catch (err) {
|
||||
addError(TransientPaperlessApiError(code: err.code));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||
|
||||
class AddNotePage extends StatefulWidget {
|
||||
final DocumentModel document;
|
||||
|
||||
const AddNotePage({super.key, required this.document});
|
||||
|
||||
@override
|
||||
State<AddNotePage> createState() => _AddNotePageState();
|
||||
}
|
||||
|
||||
class _AddNotePageState extends State<AddNotePage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(S.of(context)!.addNote),
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
TextField(
|
||||
decoration: InputDecoration(
|
||||
labelText: S.of(context)!.content,
|
||||
),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {},
|
||||
child: Text(S.of(context)!.save),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -8,18 +8,65 @@ import 'package:paperless_mobile/features/document_details/cubit/document_detail
|
||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||
import 'package:paperless_mobile/helpers/message_helpers.dart';
|
||||
|
||||
class DocumentNotesWidget extends StatelessWidget {
|
||||
class DocumentNotesWidget extends StatefulWidget {
|
||||
final DocumentModel document;
|
||||
const DocumentNotesWidget({super.key, required this.document});
|
||||
|
||||
@override
|
||||
State<DocumentNotesWidget> createState() => _DocumentNotesWidgetState();
|
||||
}
|
||||
|
||||
class _DocumentNotesWidgetState extends State<DocumentNotesWidget> {
|
||||
final _noteContentController = TextEditingController();
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SliverMainAxisGroup(
|
||||
slivers: [
|
||||
SliverToBoxAdapter(
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
children: [
|
||||
TextFormField(
|
||||
controller: _noteContentController,
|
||||
maxLines: null,
|
||||
validator: (value) {
|
||||
if (value?.isEmpty ?? true) {
|
||||
return S.of(context)!.thisFieldIsRequired;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Your note here...',
|
||||
labelText: 'New note',
|
||||
floatingLabelBehavior: FloatingLabelBehavior.always,
|
||||
),
|
||||
).padded(),
|
||||
Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: FilledButton.icon(
|
||||
icon: Icon(Icons.note_add_outlined),
|
||||
label: Text("Add note"),
|
||||
onPressed: () {
|
||||
_formKey.currentState?.save();
|
||||
if (_formKey.currentState?.validate() ?? false) {
|
||||
context
|
||||
.read<DocumentDetailsCubit>()
|
||||
.addNote(_noteContentController.text);
|
||||
}
|
||||
},
|
||||
).padded(),
|
||||
),
|
||||
],
|
||||
).padded(),
|
||||
),
|
||||
),
|
||||
SliverList.separated(
|
||||
separatorBuilder: (context, index) => const SizedBox(height: 16),
|
||||
itemBuilder: (context, index) {
|
||||
final note = document.notes.elementAt(index);
|
||||
final note = widget.document.notes.elementAt(index);
|
||||
return Card(
|
||||
// borderRadius: BorderRadius.circular(8),
|
||||
// elevation: 1,
|
||||
@@ -51,13 +98,6 @@ class DocumentNotesWidget extends StatelessWidget {
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Spacer(),
|
||||
IconButton(
|
||||
icon: Icon(Icons.edit),
|
||||
onPressed: () {
|
||||
// Push edit page
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.delete),
|
||||
onPressed: () {
|
||||
@@ -74,7 +114,7 @@ class DocumentNotesWidget extends StatelessWidget {
|
||||
).padded(16),
|
||||
);
|
||||
},
|
||||
itemCount: document.notes.length,
|
||||
itemCount: widget.document.notes.length,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class EditNotePage extends StatefulWidget {
|
||||
const EditNotePage({super.key});
|
||||
|
||||
@override
|
||||
State<EditNotePage> createState() => _EditNotePageState();
|
||||
}
|
||||
|
||||
class _EditNotePageState extends State<EditNotePage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Placeholder();
|
||||
}
|
||||
}
|
||||
@@ -54,7 +54,9 @@ class DocumentScannerCubit extends Cubit<DocumentScannerState> {
|
||||
|
||||
Future<void> removeScan(File file) async {
|
||||
try {
|
||||
await file.delete();
|
||||
if (await file.exists()) {
|
||||
await file.delete();
|
||||
}
|
||||
} catch (error, stackTrace) {
|
||||
throw InfoMessageException(
|
||||
code: ErrorCode.scanRemoveFailed,
|
||||
|
||||
@@ -14,6 +14,7 @@ import 'package:paperless_mobile/core/bloc/loading_status.dart';
|
||||
import 'package:paperless_mobile/core/database/hive/hive_config.dart';
|
||||
import 'package:paperless_mobile/core/database/tables/global_settings.dart';
|
||||
import 'package:paperless_mobile/core/global/constants.dart';
|
||||
import 'package:paperless_mobile/core/model/info_message_exception.dart';
|
||||
import 'package:paperless_mobile/core/service/file_service.dart';
|
||||
import 'package:paperless_mobile/features/app_drawer/view/app_drawer.dart';
|
||||
import 'package:paperless_mobile/features/document_scan/cubit/document_scanner_cubit.dart';
|
||||
@@ -326,6 +327,8 @@ class _ScannerPageState extends State<ScannerPage>
|
||||
.removeScan(scans[index]);
|
||||
} on PaperlessApiException catch (error, stackTrace) {
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
} on InfoMessageException catch (error, stackTrace) {
|
||||
showInfoMessage(context, error, stackTrace);
|
||||
}
|
||||
},
|
||||
index: index,
|
||||
|
||||
@@ -9,7 +9,6 @@ import 'package:paperless_mobile/features/document_bulk_action/view/widgets/full
|
||||
import 'package:paperless_mobile/features/document_bulk_action/view/widgets/fullscreen_bulk_edit_tags_widget.dart';
|
||||
import 'package:paperless_mobile/features/document_details/cubit/document_details_cubit.dart';
|
||||
import 'package:paperless_mobile/features/document_details/view/pages/document_details_page.dart';
|
||||
import 'package:paperless_mobile/features/document_details/view/widgets/add_note_page.dart';
|
||||
import 'package:paperless_mobile/features/document_edit/cubit/document_edit_cubit.dart';
|
||||
import 'package:paperless_mobile/features/document_edit/view/document_edit_page.dart';
|
||||
import 'package:paperless_mobile/features/documents/view/pages/document_view.dart';
|
||||
@@ -211,16 +210,3 @@ class BulkEditDocumentsRoute extends GoRouteData {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AddNoteRoute extends GoRouteData {
|
||||
final DocumentModel $extra;
|
||||
|
||||
AddNoteRoute({required this.$extra});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, GoRouterState state) {
|
||||
return AddNotePage(
|
||||
document: $extra,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,10 +85,6 @@ part 'authenticated_route.g.dart';
|
||||
path: 'preview',
|
||||
name: R.documentPreview,
|
||||
),
|
||||
TypedGoRoute<AddNoteRoute>(
|
||||
path: 'add-note',
|
||||
name: R.addNote,
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
|
||||
@@ -4,3 +4,4 @@ export 'src/models/models.dart';
|
||||
export 'src/modules/modules.dart';
|
||||
export 'src/converters/converters.dart';
|
||||
export 'config/hive/hive_type_ids.dart';
|
||||
export 'src/interceptor/dio_http_error_interceptor.dart';
|
||||
|
||||
@@ -125,8 +125,8 @@ class DocumentFilter extends Equatable {
|
||||
return queryParams;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() => toQueryParameters().toString();
|
||||
// @override
|
||||
// String toString() => toQueryParameters().toString();
|
||||
|
||||
DocumentFilter copyWith({
|
||||
int? pageSize,
|
||||
@@ -249,9 +249,4 @@ class DocumentFilter extends Equatable {
|
||||
moreLike,
|
||||
selectedView,
|
||||
];
|
||||
|
||||
// factory DocumentFilter.fromJson(Map<String, dynamic> json) =>
|
||||
// _$DocumentFilterFromJson(json);
|
||||
|
||||
// Map<String, dynamic> toJson() => _$DocumentFilterToJson(this);
|
||||
}
|
||||
|
||||
@@ -82,7 +82,6 @@ class FilterRule with EquatableMixin {
|
||||
assert(filter.tags is IdsTagsQuery);
|
||||
return filter.copyWith(
|
||||
tags: switch (filter.tags) {
|
||||
// TODO: Handle this case.
|
||||
IdsTagsQuery(include: var i, exclude: var e) => IdsTagsQuery(
|
||||
include: [...i, int.parse(value!)],
|
||||
exclude: e,
|
||||
|
||||
@@ -28,4 +28,4 @@ export 'task/task.dart';
|
||||
export 'task/task_status.dart';
|
||||
export 'user_model.dart';
|
||||
export 'exception/exceptions.dart';
|
||||
export 'note_model.dart';
|
||||
export 'note_model.dart' show NoteModel;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// ignore_for_file: invalid_annotation_target
|
||||
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
part 'note_model.freezed.dart';
|
||||
part 'note_model.g.dart';
|
||||
@@ -9,9 +11,19 @@ class NoteModel with _$NoteModel {
|
||||
required String? note,
|
||||
required DateTime? created,
|
||||
required int? document,
|
||||
required int? user,
|
||||
@JsonKey(fromJson: parseNoteUserFromJson) required int? user,
|
||||
}) = _NoteModel;
|
||||
|
||||
factory NoteModel.fromJson(Map<String, dynamic> json) =>
|
||||
_$NoteModelFromJson(json);
|
||||
}
|
||||
|
||||
int? parseNoteUserFromJson(dynamic json) {
|
||||
if (json == null) return null;
|
||||
if (json is Map) {
|
||||
return json['id'];
|
||||
} else if (json is int) {
|
||||
return json;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,16 @@ class PaperlessApiException implements Exception {
|
||||
this.httpStatusCode,
|
||||
});
|
||||
|
||||
const PaperlessApiException.unknown() : this(ErrorCode.unknown);
|
||||
const PaperlessApiException.unknown({
|
||||
String? details,
|
||||
StackTrace? stackTrace,
|
||||
int? httpStatusCode,
|
||||
}) : this(
|
||||
ErrorCode.unknown,
|
||||
details: details,
|
||||
stackTrace: stackTrace,
|
||||
httpStatusCode: httpStatusCode,
|
||||
);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
@@ -71,5 +80,7 @@ enum ErrorCode {
|
||||
updateSavedViewError,
|
||||
customFieldCreateFailed,
|
||||
customFieldLoadFailed,
|
||||
customFieldDeleteFailed;
|
||||
customFieldDeleteFailed,
|
||||
deleteNoteFailed,
|
||||
addNoteFailed;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import 'date_range_unit.dart';
|
||||
|
||||
part 'date_range_query.g.dart';
|
||||
|
||||
sealed class DateRangeQuery {
|
||||
sealed class DateRangeQuery with EquatableMixin {
|
||||
const DateRangeQuery();
|
||||
|
||||
Map<String, String> toQueryParameter(DateRangeQueryField field);
|
||||
@@ -28,10 +28,13 @@ class UnsetDateRangeQuery extends DateRangeQuery {
|
||||
|
||||
@override
|
||||
bool matches(DateTime dt) => true;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
@HiveType(typeId: PaperlessApiHiveTypeIds.relativeDateRangeQuery)
|
||||
class RelativeDateRangeQuery extends DateRangeQuery with EquatableMixin {
|
||||
class RelativeDateRangeQuery extends DateRangeQuery {
|
||||
@HiveField(0)
|
||||
final int offset;
|
||||
@HiveField(1)
|
||||
@@ -84,7 +87,7 @@ class RelativeDateRangeQuery extends DateRangeQuery with EquatableMixin {
|
||||
|
||||
@JsonSerializable()
|
||||
@HiveType(typeId: PaperlessApiHiveTypeIds.absoluteDateRangeQuery)
|
||||
class AbsoluteDateRangeQuery extends DateRangeQuery with EquatableMixin {
|
||||
class AbsoluteDateRangeQuery extends DateRangeQuery {
|
||||
@LocalDateTimeJsonConverter()
|
||||
@HiveField(0)
|
||||
final DateTime? after;
|
||||
|
||||
@@ -4,7 +4,7 @@ import 'package:paperless_api/config/hive/hive_type_ids.dart';
|
||||
|
||||
part 'id_query_parameter.g.dart';
|
||||
|
||||
sealed class IdQueryParameter {
|
||||
sealed class IdQueryParameter with EquatableMixin {
|
||||
const IdQueryParameter();
|
||||
Map<String, String> toQueryParameter(String field);
|
||||
bool matches(int? id);
|
||||
@@ -23,6 +23,9 @@ class UnsetIdQueryParameter extends IdQueryParameter {
|
||||
|
||||
@override
|
||||
bool matches(int? id) => true;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
// @HiveType(typeId: PaperlessApiHiveTypeIds.notAssignedIdQueryParameter)
|
||||
@@ -36,6 +39,8 @@ class NotAssignedIdQueryParameter extends IdQueryParameter {
|
||||
|
||||
@override
|
||||
bool matches(int? id) => id == null;
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
// @HiveType(typeId: PaperlessApiHiveTypeIds.anyAssignedIdQueryParameter)
|
||||
@@ -48,6 +53,8 @@ class AnyAssignedIdQueryParameter extends IdQueryParameter {
|
||||
|
||||
@override
|
||||
bool matches(int? id) => id != null;
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
@HiveType(typeId: PaperlessApiHiveTypeIds.setIdQueryParameter)
|
||||
|
||||
@@ -4,7 +4,7 @@ import 'package:paperless_api/config/hive/hive_type_ids.dart';
|
||||
|
||||
part 'tags_query.g.dart';
|
||||
|
||||
sealed class TagsQuery {
|
||||
sealed class TagsQuery with EquatableMixin {
|
||||
const TagsQuery();
|
||||
Map<String, String> toQueryParameter();
|
||||
bool matches(Iterable<int> ids);
|
||||
@@ -20,10 +20,13 @@ class NotAssignedTagsQuery extends TagsQuery {
|
||||
|
||||
@override
|
||||
bool matches(Iterable<int> ids) => ids.isEmpty;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
@HiveType(typeId: PaperlessApiHiveTypeIds.anyAssignedTagsQuery)
|
||||
class AnyAssignedTagsQuery extends TagsQuery with EquatableMixin {
|
||||
class AnyAssignedTagsQuery extends TagsQuery {
|
||||
@HiveField(0)
|
||||
final List<int> tagIds;
|
||||
const AnyAssignedTagsQuery({
|
||||
@@ -54,7 +57,7 @@ class AnyAssignedTagsQuery extends TagsQuery with EquatableMixin {
|
||||
}
|
||||
|
||||
@HiveType(typeId: PaperlessApiHiveTypeIds.idsTagsQuery)
|
||||
class IdsTagsQuery extends TagsQuery with EquatableMixin {
|
||||
class IdsTagsQuery extends TagsQuery {
|
||||
@HiveField(0)
|
||||
final List<int> include;
|
||||
@HiveField(1)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:paperless_api/config/hive/hive_type_ids.dart';
|
||||
@@ -91,6 +92,11 @@ class TextQuery {
|
||||
return other.queryText == queryText && other.queryType == queryType;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return "TextQuery($queryText, $queryType)";
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(queryText, queryType);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
import 'package:paperless_api/src/models/exception/exceptions.dart';
|
||||
|
||||
abstract class PaperlessAuthenticationApi {
|
||||
///
|
||||
/// @throws [PaperlessUnauthorizedException]
|
||||
///
|
||||
Future<String> login({
|
||||
required String username,
|
||||
required String password,
|
||||
|
||||
@@ -37,6 +37,11 @@ class PaperlessAuthenticationApiImpl implements PaperlessAuthenticationApi {
|
||||
// return AuthenticationTemporaryRedirect(redirectUrl!);
|
||||
} on DioException catch (exception) {
|
||||
throw exception.unravel();
|
||||
} catch (error, stackTrace) {
|
||||
throw PaperlessApiException.unknown(
|
||||
details: error.toString(),
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,4 +36,7 @@ abstract class PaperlessDocumentsApi {
|
||||
Future<FieldSuggestions> findSuggestions(DocumentModel document);
|
||||
|
||||
Future<List<String>> autocomplete(String query, [int limit = 10]);
|
||||
|
||||
Future<DocumentModel> addNote(
|
||||
{required DocumentModel document, required String text});
|
||||
}
|
||||
|
||||
@@ -337,7 +337,30 @@ class PaperlessDocumentsApiImpl implements PaperlessDocumentsApi {
|
||||
return document.copyWith(notes: notes);
|
||||
} on DioException catch (exception) {
|
||||
throw exception.unravel(
|
||||
orElse: const PaperlessApiException(ErrorCode.documentDeleteFailed),
|
||||
orElse: const PaperlessApiException(ErrorCode.deleteNoteFailed),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<DocumentModel> addNote({
|
||||
required DocumentModel document,
|
||||
required String text,
|
||||
}) async {
|
||||
try {
|
||||
final response = await client.post(
|
||||
"/api/documents/${document.id}/notes/",
|
||||
options: Options(validateStatus: (status) => status == 200),
|
||||
data: {'note': text},
|
||||
);
|
||||
|
||||
final notes =
|
||||
(response.data as List).map((e) => NoteModel.fromJson(e)).toList();
|
||||
|
||||
return document.copyWith(notes: notes);
|
||||
} on DioException catch (exception) {
|
||||
throw exception.unravel(
|
||||
orElse: const PaperlessApiException(ErrorCode.addNoteFailed),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ dependencies:
|
||||
jiffy: ^5.0.0
|
||||
freezed_annotation: ^2.4.1
|
||||
hive: ^2.2.3
|
||||
mockito: ^5.4.4
|
||||
http_mock_adapter: ^0.6.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:http_mock_adapter/http_mock_adapter.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
|
||||
void main() {
|
||||
group('AuthenticationApi with DioHttpErrorIncerceptor', () {
|
||||
late PaperlessAuthenticationApi authenticationApi;
|
||||
late DioAdapter mockAdapter;
|
||||
const token = "abcde";
|
||||
const invalidCredentialsServerMessage =
|
||||
"Unable to log in with provided credentials.";
|
||||
|
||||
setUp(() {
|
||||
final dio = Dio()..interceptors.add(DioHttpErrorInterceptor());
|
||||
authenticationApi = PaperlessAuthenticationApiImpl(dio);
|
||||
mockAdapter = DioAdapter(dio: dio);
|
||||
// Valid credentials
|
||||
mockAdapter.onPost(
|
||||
"/api/token/",
|
||||
data: {
|
||||
"username": "username",
|
||||
"password": "password",
|
||||
},
|
||||
(server) => server.reply(200, {"token": token}),
|
||||
);
|
||||
// Invalid credentials
|
||||
mockAdapter.onPost(
|
||||
"/api/token/",
|
||||
data: {
|
||||
"username": "wrongUsername",
|
||||
"password": "wrongPassword",
|
||||
},
|
||||
(server) => server.reply(400, {
|
||||
"non_field_errors": [invalidCredentialsServerMessage]
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
// tearDown(() {});
|
||||
test(
|
||||
'should return a valid token when logging in with valid credentials',
|
||||
() {
|
||||
expect(
|
||||
authenticationApi.login(
|
||||
username: "username",
|
||||
password: "password",
|
||||
),
|
||||
completion(token),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
'should throw a PaperlessFormValidationException containing a reason '
|
||||
'when logging in with invalid credentials',
|
||||
() {
|
||||
expect(
|
||||
authenticationApi.login(
|
||||
username: "wrongUsername",
|
||||
password: "wrongPassword",
|
||||
),
|
||||
throwsA(isA<PaperlessFormValidationException>().having(
|
||||
(e) => e.unspecificErrorMessage(),
|
||||
"non-field specific error message",
|
||||
equals(invalidCredentialsServerMessage),
|
||||
)),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
'should return an error when logging in with invalid credentials',
|
||||
() {
|
||||
expect(
|
||||
authenticationApi.login(
|
||||
username: "wrongUsername",
|
||||
password: "wrongPassword",
|
||||
),
|
||||
throwsA(isA<PaperlessFormValidationException>().having(
|
||||
(e) => e.unspecificErrorMessage(),
|
||||
"non-field specific error message",
|
||||
equals(invalidCredentialsServerMessage),
|
||||
)),
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
|
||||
void main() {
|
||||
group('Validate parsing logic from [SavedView] to [DocumentFilter]:', () {
|
||||
group('Parsing [SavedView] to [DocumentFilter]:', () {
|
||||
test('Values are correctly parsed if set.', () {
|
||||
expect(
|
||||
SavedView.fromJson({
|
||||
@@ -64,7 +64,7 @@ void main() {
|
||||
]
|
||||
}).toDocumentFilter(),
|
||||
equals(
|
||||
DocumentFilter.initial.copyWith(
|
||||
DocumentFilter(
|
||||
correspondent: const SetIdQueryParameter(id: 42),
|
||||
documentType: const SetIdQueryParameter(id: 69),
|
||||
storagePath: const SetIdQueryParameter(id: 14),
|
||||
@@ -83,6 +83,7 @@ void main() {
|
||||
sortField: SortField.created,
|
||||
sortOrder: SortOrder.descending,
|
||||
query: const TextQuery.extended("Never gonna give you up"),
|
||||
selectedView: 1,
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -99,7 +100,11 @@ void main() {
|
||||
"sort_reverse": true,
|
||||
"filter_rules": [],
|
||||
}).toDocumentFilter(),
|
||||
equals(DocumentFilter.initial),
|
||||
equals(
|
||||
const DocumentFilter(
|
||||
selectedView: 1,
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -130,11 +135,12 @@ void main() {
|
||||
},
|
||||
],
|
||||
}).toDocumentFilter();
|
||||
final expected = DocumentFilter.initial.copyWith(
|
||||
correspondent: const NotAssignedIdQueryParameter(),
|
||||
documentType: const NotAssignedIdQueryParameter(),
|
||||
storagePath: const NotAssignedIdQueryParameter(),
|
||||
tags: const NotAssignedTagsQuery(),
|
||||
const expected = DocumentFilter(
|
||||
correspondent: NotAssignedIdQueryParameter(),
|
||||
documentType: NotAssignedIdQueryParameter(),
|
||||
storagePath: NotAssignedIdQueryParameter(),
|
||||
tags: NotAssignedTagsQuery(),
|
||||
selectedView: 1,
|
||||
);
|
||||
expect(
|
||||
actual,
|
||||
@@ -148,6 +154,7 @@ void main() {
|
||||
expect(
|
||||
SavedView.fromDocumentFilter(
|
||||
DocumentFilter(
|
||||
selectedView: 1,
|
||||
correspondent: const SetIdQueryParameter(id: 1),
|
||||
documentType: const SetIdQueryParameter(id: 2),
|
||||
storagePath: const SetIdQueryParameter(id: 3),
|
||||
@@ -173,6 +180,7 @@ void main() {
|
||||
),
|
||||
equals(
|
||||
SavedView(
|
||||
id: 1,
|
||||
name: "test_name",
|
||||
showOnDashboard: false,
|
||||
showInSidebar: false,
|
||||
Reference in New Issue
Block a user