import 'package:flutter_test/flutter_test.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:miler/data/service_profile.dart'; /// ───────────────────────────────────────────────────────────────────────── /// WHAT `tenantname` ON THE LOGIN IS WORTH /// /// The backend gates `MILER_COLLECTED_STATE_ENABLED` on every hyperlocal rider /// having a **Start delivery** button, because with the flag on a parcel with /// nobody to release it sits at `Collected_By_Miler` forever. /// /// That button is not a build flag. It is [ServiceProfile.deliversToCustomer], /// resolved per-login from the rider's tenant — so the question is not *which /// build is installed* but *does this rider resolve to the milk-run profile*. /// /// ── Two ways to answer, and only one of them scales ── /// /// ``` /// by id a hardcoded set, {13} today. A client whose id we were never /// told falls through to logistics and gets no button. /// by name matched against `tenantname`, checked FIRST. `dailygrubs` is /// already on the list, so the client resolves with no release. /// ``` /// /// `tenantname` is not deployed yet, which is the whole of the risk: every /// hyperlocal tenant that is not id 13 is currently a strand waiting for the /// flag to be turned on. These pin both halves — that the name is sufficient /// on its own, and what happens without it. /// ───────────────────────────────────────────────────────────────────────── void main() { TestWidgetsFlutterBinding.ensureInitialized(); tearDown(() => ServiceProfile.setActive(ServiceProfile.parcel)); test( 'the name alone puts a DailyGrubs rider on the milk-run profile', () async { // Deliberately no tenant id: this is a client whose id this app has never // been told, which is exactly the case the id set cannot cover. SharedPreferences.setMockInitialValues({ TenantController.kTenantName: 'DailyGrubs', }); final profile = await resolveServiceProfile(); expect(profile, ServiceProfile.milkMan); expect( profile.deliversToCustomer, isTrue, reason: 'this is the flag that renders Start delivery', ); }, ); test('case and spacing do not decide a rider\'s day', () async { for (final spelling in const [ 'dailygrubs', 'DAILYGRUBS', ' DailyGrubs ', // How a human actually types a client name into a tenant record. Each of // these used to miss, and a miss is a rider with no Start delivery button // and a parcel stranded at `Collected_By_Miler`. 'Daily Grubs', 'daily-grubs', 'DAILY_GRUBS', ]) { SharedPreferences.setMockInitialValues({ TenantController.kTenantName: spelling, }); expect( await resolveServiceProfile(), ServiceProfile.milkMan, reason: '"$spelling" did not resolve', ); } }); test('without it, an unrecognised tenant falls back to logistics', () async { // The strand: flag on, newest build installed, no button to press, and the // parcel stays at `Collected_By_Miler` because nothing can release it. SharedPreferences.setMockInitialValues({TenantController.kTenantId: 17}); final profile = await resolveServiceProfile(); expect(profile, ServiceProfile.parcel); expect(profile.deliversToCustomer, isFalse); }); test('the name decides when the id says nothing', () async { // Belt and braces: a hyperlocal client sitting on an id this app has not // been told about must still resolve from its name. // // Note 17 is *unlisted*, not contradictory — an id this build knows wins, // see `tenant_mode_test.dart`. This is the fall-through, which is the whole // reason a new client needs no release. SharedPreferences.setMockInitialValues({ TenantController.kTenantName: 'DailyGrubs', TenantController.kTenantId: 17, }); expect(await resolveServiceProfile(), ServiceProfile.milkMan); }); }