feat(studio): show a source module's data terms before the install button
Some checks failed
Security / Security check (push) Failing after 2s
Some checks failed
Security / Security check (push) Failing after 2s
The store detail sheet now carries a data-source block for source.* modules: publisher, upstream url, the terms in plain words, and any attribution the operator has to carry with the output. It sits above maintainers and above the install button, because it is a decision input rather than a footnote. The values are selectable: compliance notes get written by copying, not retyping. A note names whose terms these are, so nobody reads them as the module's own licence. Four guards, including that an empty attribution renders no empty row. Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
parent
fb809a4cbd
commit
35a79d0bb6
8 changed files with 307 additions and 44 deletions
85
test/store_data_source_test.dart
Normal file
85
test/store_data_source_test.dart
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
// Guards for the data-provenance block in the store detail sheet.
|
||||
//
|
||||
// The rule it protects (docs/architecture/store-format.md): the terms
|
||||
// of the material a source module fetches are separate from the
|
||||
// module's own licence, and an operator must see them before the
|
||||
// install button, not in a README afterwards.
|
||||
|
||||
import 'package:chain_studio/data/hub.dart';
|
||||
import 'package:chain_studio/l10n/app_localizations.dart';
|
||||
import 'package:chain_studio/pages/store.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
Widget _host(Widget child) => MaterialApp(
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
locale: const Locale('de'),
|
||||
home: Scaffold(body: SingleChildScrollView(child: child)),
|
||||
);
|
||||
|
||||
void main() {
|
||||
const bund = DataProvenance(
|
||||
name: 'gesetze-im-internet.de (BMJ / juris GmbH)',
|
||||
url: 'https://www.gesetze-im-internet.de/',
|
||||
license: 'Amtliches Werk (§ 5 UrhG), gemeinfrei',
|
||||
attribution: 'Quelle: gesetze-im-internet.de (Bundesministerium der Justiz)',
|
||||
);
|
||||
|
||||
testWidgets('publisher, terms and attribution are all shown',
|
||||
(tester) async {
|
||||
await tester.pumpWidget(_host(const StoreDataSourceSection(source: bund)));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text(bund.name), findsOneWidget);
|
||||
expect(find.text(bund.url), findsOneWidget);
|
||||
expect(find.text(bund.license), findsOneWidget);
|
||||
expect(find.text(bund.attribution), findsOneWidget,
|
||||
reason: 'an attribution duty must be visible before installing');
|
||||
});
|
||||
|
||||
testWidgets('the attribution row is omitted when none is required',
|
||||
(tester) async {
|
||||
const noAttribution = DataProvenance(
|
||||
name: 'Vom Betreiber gepflegter Metadaten-Katalog',
|
||||
url: '',
|
||||
license: 'Katalog des Betreibers',
|
||||
attribution: '',
|
||||
);
|
||||
await tester
|
||||
.pumpWidget(_host(const StoreDataSourceSection(source: noAttribution)));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text(noAttribution.name), findsOneWidget);
|
||||
final l = AppLocalizations.of(
|
||||
tester.element(find.byType(StoreDataSourceSection)),
|
||||
)!;
|
||||
expect(find.text(l.storeDataSourceAttribution), findsNothing,
|
||||
reason: 'an empty attribution must not render an empty row');
|
||||
});
|
||||
|
||||
testWidgets('the terms are selectable so they can be copied',
|
||||
(tester) async {
|
||||
await tester.pumpWidget(_host(const StoreDataSourceSection(source: bund)));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Compliance notes get written by copying, not retyping.
|
||||
expect(
|
||||
find.byWidgetPredicate(
|
||||
(w) => w is SelectableText && w.data == bund.attribution,
|
||||
),
|
||||
findsOneWidget,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('the note says whose terms these are', (tester) async {
|
||||
await tester.pumpWidget(_host(const StoreDataSourceSection(source: bund)));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final l = AppLocalizations.of(
|
||||
tester.element(find.byType(StoreDataSourceSection)),
|
||||
)!;
|
||||
// Without this line an operator reads the terms as the module's.
|
||||
expect(find.text(l.storeDataSourceNote), findsOneWidget);
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue