production
This commit is contained in:
121
test/tenant_refresh_test.dart
Normal file
121
test/tenant_refresh_test.dart
Normal file
@@ -0,0 +1,121 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:http/testing.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import 'package:miler/data/miler_api.dart';
|
||||
import 'package:miler/data/service_profile.dart';
|
||||
|
||||
/// ─────────────────────────────────────────────────────────────────────────
|
||||
/// THE TENANT, REFRESHED WITHOUT A SIGN-OUT
|
||||
///
|
||||
/// `tenantname` was written at verify-pin and nowhere else, so it only reached
|
||||
/// a device by way of a **login**. A rider already signed in when the backend
|
||||
/// began returning the field would never receive it: prefs carry no name,
|
||||
/// resolution falls back to the tenant id, and an id this app has not been told
|
||||
/// about lands him on logistics — no **Start delivery** button, and a parcel
|
||||
/// stranded at `Collected_By_Miler` the moment collected-state is enabled.
|
||||
///
|
||||
/// `GET /miler/profile` returns the same pair, so the answer is refreshable in
|
||||
/// place. These pin that, and pin the three ways it must fail quietly: a launch
|
||||
/// with no signal, a signed-out device, and a handler that answers without the
|
||||
/// field.
|
||||
/// ─────────────────────────────────────────────────────────────────────────
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
tearDown(() {
|
||||
MilerApi.client = http.Client();
|
||||
ServiceProfile.setActive(ServiceProfile.parcel);
|
||||
});
|
||||
|
||||
void stubProfile(Map<String, dynamic> body, {int code = 200}) {
|
||||
MilerApi.client = MockClient(
|
||||
(req) async => http.Response(
|
||||
json.encode(body),
|
||||
code,
|
||||
headers: const {'content-type': 'application/json'},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
test('a signed-in rider picks up his tenant name in place', () async {
|
||||
SharedPreferences.setMockInitialValues({'authtoken': 'tok'});
|
||||
stubProfile({
|
||||
'success': true,
|
||||
'data': {'tenantid': 41, 'tenantname': 'DailyGrubs'},
|
||||
});
|
||||
|
||||
await refreshTenantFromProfile();
|
||||
|
||||
expect(
|
||||
await resolveServiceProfile(),
|
||||
ServiceProfile.milkMan,
|
||||
reason: 'no sign-out should be required to receive the tenant',
|
||||
);
|
||||
});
|
||||
|
||||
test('the pair is read from inside `user` as well as top level', () async {
|
||||
// The backend returns it both ways; a handler that later moves it must not
|
||||
// silently stop resolving riders.
|
||||
SharedPreferences.setMockInitialValues({'authtoken': 'tok'});
|
||||
stubProfile({
|
||||
'success': true,
|
||||
'data': {
|
||||
'user': {'tenantid': 41, 'tenantname': 'Daily Grubs'},
|
||||
},
|
||||
});
|
||||
|
||||
await refreshTenantFromProfile();
|
||||
expect(await resolveServiceProfile(), ServiceProfile.milkMan);
|
||||
});
|
||||
|
||||
test('a signed-out device asks for nothing', () async {
|
||||
var called = false;
|
||||
MilerApi.client = MockClient((req) async {
|
||||
called = true;
|
||||
return http.Response('{}', 200);
|
||||
});
|
||||
|
||||
SharedPreferences.setMockInitialValues(const {});
|
||||
await refreshTenantFromProfile();
|
||||
|
||||
expect(called, isFalse, reason: 'no token, no request');
|
||||
});
|
||||
|
||||
test('a launch with no signal keeps what it already had', () async {
|
||||
SharedPreferences.setMockInitialValues({
|
||||
'authtoken': 'tok',
|
||||
TenantController.kTenantName: 'DailyGrubs',
|
||||
});
|
||||
MilerApi.client = MockClient((req) async => throw const SocketishFailure());
|
||||
|
||||
// Must not throw: a launch offline lands on the same screen it always did.
|
||||
await refreshTenantFromProfile();
|
||||
expect(await resolveServiceProfile(), ServiceProfile.milkMan);
|
||||
});
|
||||
|
||||
test('a response without the field does not erase the stored one', () async {
|
||||
SharedPreferences.setMockInitialValues({
|
||||
'authtoken': 'tok',
|
||||
TenantController.kTenantName: 'DailyGrubs',
|
||||
});
|
||||
stubProfile({
|
||||
'success': true,
|
||||
'data': {'displayname': 'Rajan A'},
|
||||
});
|
||||
|
||||
await refreshTenantFromProfile();
|
||||
// Backgrounded for a known rider, so let it land before asserting.
|
||||
await Future<void>.delayed(const Duration(milliseconds: 50));
|
||||
expect(await resolveServiceProfile(), ServiceProfile.milkMan);
|
||||
});
|
||||
}
|
||||
|
||||
/// A stand-in for a dead network, so the test does not depend on `dart:io`
|
||||
/// error construction details.
|
||||
class SocketishFailure implements Exception {
|
||||
const SocketishFailure();
|
||||
}
|
||||
Reference in New Issue
Block a user