Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ abstract class QuestionFormData implements IFormData {
final QuestionConditional? conditional;

/// Mapping from response option => qualifying/disqualifying
late final Map<dynamic, bool> responseOptionsValidity;
Map<dynamic, bool> responseOptionsValidity = {};

List<dynamic> get responseOptions; // subclass responsibility

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ extension FormViewModelCollectionActions<
final duplicateFormViewModel =
formViewModel.createDuplicate() as T;
add(duplicateFormViewModel);
formViewModel.save();
duplicateFormViewModel.save();
},
isAvailable: !isReadOnly,
),
Expand Down
6 changes: 6 additions & 0 deletions designer_v2/lib/localization/app_translation.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:flutter/foundation.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:studyu_designer_v2/localization/app_localizations.dart';
import 'package:studyu_designer_v2/localization/locale_providers.dart';
Expand All @@ -11,6 +12,11 @@ class AppTranslation {
// Loads the currently selected locale and sets the localization
_tr = lookupAppLocalizations(ref.watch(localeProvider));
}

@visibleForTesting
static void setForTesting(AppLocalizations localizations) {
_tr = localizations;
}
}

typedef LocalizedStringResolver = String Function();
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import 'package:reactive_forms/reactive_forms.dart';
import 'package:studyu_designer_v2/features/design/shared/questionnaire/question/question_form_data.dart';
import 'package:studyu_designer_v2/features/design/shared/questionnaire/question/types/question_type.dart';
import 'package:studyu_designer_v2/features/forms/form_data.dart';
import 'package:studyu_designer_v2/features/forms/form_view_model.dart';
import 'package:studyu_designer_v2/features/forms/form_view_model_collection.dart';
import 'package:studyu_designer_v2/features/forms/form_view_model_collection_actions.dart';
import 'package:studyu_designer_v2/localization/app_localizations_en.dart';
import 'package:studyu_designer_v2/localization/app_translation.dart';
import 'package:studyu_designer_v2/utils/model_action.dart';
import 'package:test/test.dart';

class _TestFormData implements IFormData {
_TestFormData({required this.id, required this.value});

@override
final String id;
final String value;

@override
_TestFormData copy() => _TestFormData(id: '${id}_copy', value: value);
}

class _TestFormViewModel extends ManagedFormViewModel<_TestFormData> {
_TestFormViewModel({super.formData, this.duplicate});

final _TestFormViewModel? duplicate;
final FormControl<String> valueControl = FormControl<String>(value: '');
int saveCount = 0;

@override
late final FormGroup form = FormGroup({'value': valueControl});

@override
Map<FormMode, String> get titles => {};

@override
void setControlsFrom(_TestFormData data) {
valueControl.value = data.value;
}

@override
_TestFormData buildFormData() {
return _TestFormData(id: formData?.id ?? 'new', value: valueControl.value!);
}

@override
_TestFormViewModel createDuplicate() {
return duplicate ?? _TestFormViewModel(formData: formData?.copy());
}

@override
Future save() {
saveCount += 1;
return super.save();
}
}

void main() {
setUpAll(() {
AppTranslation.setForTesting(AppLocalizationsEn());
});

test('duplicate action saves the duplicated view model', () async {
final formArray = FormArray([]);
final duplicate = _TestFormViewModel(
formData: _TestFormData(id: 'duplicate', value: 'Question copy'),
);
final original = _TestFormViewModel(
formData: _TestFormData(id: 'original', value: 'Question'),
duplicate: duplicate,
);
final collection =
FormViewModelCollection<_TestFormViewModel, _TestFormData>([
original,
], formArray);
formArray.add(original.form);

final duplicateAction = collection
.availableActions(original)
.singleWhere((action) => action.type == ModelActionType.duplicate);

duplicateAction.onExecute();
await Future<void>.delayed(Duration.zero);

expect(collection.formViewModels, [original, duplicate]);
expect(original.saveCount, 0);
expect(duplicate.saveCount, 1);
});

test(
'question data can be copied before response validity is initialized',
() {
final data = BoolQuestionFormData(
questionId: 'question-1',
questionText: 'Temporary duplicate test',
questionType: SurveyQuestionType.bool,
);

final duplicate = data.copy();

expect(duplicate.questionId, isNot(data.questionId));
expect(duplicate.questionText, 'Temporary duplicate test (Copy)');
expect(duplicate.responseOptionsValidity, isEmpty);
},
);
}
Loading