import 'package:flutter_test/flutter_test.dart'; import 'package:nearle_pos/data/datasources/local_store.dart'; import 'package:nearle_pos/data/local/staff_dao.dart'; import 'package:nearle_pos/domain/entities/store_account.dart'; /// The till shipped with three names and three PINs compiled into it — /// Suriya/4821, Divya/5093, Rahul/6274 — identical on every install and /// readable by anyone with the APK. They existed because a shop with nothing in /// its back office still has to trade on day one, and that is still true: only /// 116 of 596 accounts on the platform have a PIN, and the outlet this build /// ships pointed at has none at all. /// /// So they stay, as a last resort, and these cover the thing that makes that /// safe: real staff must *retire* them rather than sit alongside them. StaffDao get staff => LocalStore.instance.staff; void main() { TestWidgetsFlutterBinding.ensureInitialized(); setUp(() async { await LocalStore.instance.reset(); }); test('a fresh till has the seeded accounts and they work', () async { final seeded = await staff.all(); expect(seeded, hasLength(3)); expect(await staff.authenticate('4821'), isNotNull); // Every one is flagged, so the first person in is made to change it. expect(seeded.every((s) => s.mustChangePin), isTrue); }); test('real staff retire the built-in PINs', () async { // The whole point. Without this the hardcoded logins would survive next to // the real ones for ever, on every terminal in the fleet. await staff.replaceFromBackOffice(const [ StaffImportRecord( localId: 'boffice-1229', name: 'Selvapuram', role: StaffRole.manager, pin: '7391', ), ]); expect(await staff.authenticate('7391'), isNotNull, reason: 'the imported account must work'); expect(await staff.authenticate('4821'), isNull, reason: 'Suriya was compiled into the app and must be gone'); expect(await staff.authenticate('5093'), isNull); expect(await staff.authenticate('6274'), isNull); }); test('an empty answer leaves a working till alone', () async { // The common case: most outlets have nobody recorded. Wiping the logins // because the back office has not been filled in yet would close a shop. final written = await staff.replaceFromBackOffice(const []); expect(written, 0); expect(await staff.authenticate('4821'), isNotNull); }); test('a leaver loses the till on the next sign-in', () async { await staff.replaceFromBackOffice(const [ StaffImportRecord( localId: 'boffice-1', name: 'Asha', role: StaffRole.cashier, pin: '7391'), StaffImportRecord( localId: 'boffice-2', name: 'Ravi', role: StaffRole.cashier, pin: '8402'), ]); expect(await staff.authenticate('8402'), isNotNull); // Ravi is removed in the back office. await staff.replaceFromBackOffice(const [ StaffImportRecord( localId: 'boffice-1', name: 'Asha', role: StaffRole.cashier, pin: '7391'), ]); expect(await staff.authenticate('7391'), isNotNull); expect(await staff.authenticate('8402'), isNull); }); test('re-syncing the same person updates rather than duplicates', () async { // Keyed on the back office user id, so a shop that changes somebody's PIN // gets one account with a new PIN, not two accounts with one each. await staff.replaceFromBackOffice(const [ StaffImportRecord( localId: 'boffice-1', name: 'Asha', role: StaffRole.cashier, pin: '7391'), ]); await staff.replaceFromBackOffice(const [ StaffImportRecord( localId: 'boffice-1', name: 'Asha Kumar', role: StaffRole.manager, pin: '8402'), ]); final all = await staff.all(); expect(all, hasLength(1)); expect(all.single.name, 'Asha Kumar'); expect(all.single.role, StaffRole.manager); expect(await staff.authenticate('8402'), isNotNull); expect(await staff.authenticate('7391'), isNull); }); test('an imported PIN is not flagged for change', () async { // It was set by the shop in the back office, so it is already theirs. The // flag is for the seeds, which everyone shares. await staff.replaceFromBackOffice(const [ StaffImportRecord( localId: 'boffice-1', name: 'Asha', role: StaffRole.cashier, pin: '7391'), ]); final imported = await staff.authenticate('7391'); expect(imported!.mustChangePin, isFalse); }); test('an unusable PIN is skipped rather than written', () async { // A name on screen that nobody can sign in as reads as a broken terminal. // `pin = 0` is the single most common value in app_users. await staff.replaceFromBackOffice(const [ StaffImportRecord( localId: 'boffice-1', name: 'No PIN', role: StaffRole.cashier, pin: '0'), StaffImportRecord( localId: 'boffice-2', name: 'Blank', role: StaffRole.cashier, pin: ''), StaffImportRecord( localId: 'boffice-3', name: 'Usable', role: StaffRole.cashier, pin: '7391'), ]); final all = await staff.all(); expect(all, hasLength(1)); expect(all.single.name, 'Usable'); }); test('an answer of nothing usable does not strand the till', () async { // Every row unusable is not the same as a deliberate empty list, but it has // to behave the same way — otherwise a back office full of `pin = 0` rows // would deactivate the seeds and leave nobody able to sign in. final written = await staff.replaceFromBackOffice(const [ StaffImportRecord( localId: 'boffice-1', name: 'No PIN', role: StaffRole.cashier, pin: '0'), ]); expect(written, 0); expect(await staff.authenticate('4821'), isNotNull, reason: 'the seeds must survive an import that wrote nobody'); }); }