// 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); }); }