Closes the physical↔digital loop the labels opened: the QR on a printed envelope (tane://seed, already encoded by seed_label_codec) can now be scanned from the inventory bar. A known label opens its variety; an unknown one asks before adding anything, then creates the variety (species linked by exact scientific name when bundled) with a lot carrying the label's year and origin. Scanner is pure ZXing (zxing_barcode_scanner, MIT) — no ML Kit, no Play Services, F-Droid-safe, the stack Ğ1nkgo ships. Mobile-only; other platforms don't show the button (OCR precedent). The post-scan flow is a plain function (handleScannedPayload) so it's widget-tested without a camera.
109 lines
3.3 KiB
Dart
109 lines
3.3 KiB
Dart
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:tane/data/export_import/seed_label_codec.dart';
|
|
import 'package:tane/data/species_repository.dart';
|
|
import 'package:tane/db/database.dart';
|
|
import 'package:tane/services/seed_label_scan.dart';
|
|
|
|
import '../support/test_support.dart';
|
|
|
|
void main() {
|
|
late AppDatabase db;
|
|
late var repo = newTestRepository(db);
|
|
late SpeciesRepository species;
|
|
|
|
setUp(() {
|
|
db = newTestDatabase();
|
|
repo = newTestRepository(db);
|
|
species = newTestSpeciesRepository(db);
|
|
});
|
|
|
|
tearDown(() async => db.close());
|
|
|
|
group('resolveScannedLabel', () {
|
|
test('rejects anything that is not a seed label', () async {
|
|
expect(
|
|
await resolveScannedLabel(repo, 'https://example.org'),
|
|
const SeedScanResult.notALabel(),
|
|
);
|
|
expect(
|
|
await resolveScannedLabel(repo, 'gibberish'),
|
|
const SeedScanResult.notALabel(),
|
|
);
|
|
});
|
|
|
|
test('finds the existing variety by its label, case-insensitively',
|
|
() async {
|
|
final id = await repo.addQuickVariety(label: 'Tomate Rosa');
|
|
final raw = SeedLabelCodec.encode(
|
|
const SeedLabelData(varietyLabel: 'tomate rosa'),
|
|
);
|
|
expect(
|
|
await resolveScannedLabel(repo, raw),
|
|
SeedScanResult.match(id),
|
|
);
|
|
});
|
|
|
|
test('an unknown label comes back with its data for the add prompt',
|
|
() async {
|
|
final raw = SeedLabelCodec.encode(
|
|
const SeedLabelData(
|
|
varietyLabel: 'Acelga de Perales',
|
|
scientificName: 'Beta vulgaris',
|
|
year: 2024,
|
|
origin: 'María · Aiako',
|
|
),
|
|
);
|
|
final result = await resolveScannedLabel(repo, raw);
|
|
expect(result.data?.varietyLabel, 'Acelga de Perales');
|
|
expect(result.data?.year, 2024);
|
|
});
|
|
});
|
|
|
|
group('importScannedLabel', () {
|
|
test('creates the variety with a lot carrying year and origin', () async {
|
|
const data = SeedLabelData(
|
|
varietyLabel: 'Acelga de Perales',
|
|
year: 2024,
|
|
origin: 'María · Aiako',
|
|
);
|
|
final varietyId = await importScannedLabel(
|
|
repository: repo,
|
|
species: species,
|
|
data: data,
|
|
);
|
|
final varieties = await db.select(db.varieties).get();
|
|
expect(varieties.single.id, varietyId);
|
|
expect(varieties.single.label, 'Acelga de Perales');
|
|
final lots = await db.select(db.lots).get();
|
|
expect(lots.single.varietyId, varietyId);
|
|
expect(lots.single.harvestYear, 2024);
|
|
expect(lots.single.originName, 'María · Aiako');
|
|
});
|
|
|
|
test('links the species by exact scientific name when bundled', () async {
|
|
await species.seedBundled(const [
|
|
SpeciesSeed(
|
|
scientificName: 'Beta vulgaris',
|
|
family: 'Amaranthaceae',
|
|
commonNames: {
|
|
'es': ['Acelga'],
|
|
},
|
|
),
|
|
]);
|
|
const data = SeedLabelData(
|
|
varietyLabel: 'Una acelga cualquiera',
|
|
scientificName: 'beta vulgaris',
|
|
);
|
|
final varietyId = await importScannedLabel(
|
|
repository: repo,
|
|
species: species,
|
|
data: data,
|
|
);
|
|
final variety = await (db.select(
|
|
db.varieties,
|
|
)..where((v) => v.id.equals(varietyId))).getSingle();
|
|
final bundled = await db.select(db.species).get();
|
|
expect(variety.speciesId, bundled.single.id);
|
|
});
|
|
});
|
|
}
|