122 lines
4.4 KiB
Dart
122 lines
4.4 KiB
Dart
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();
|
|
}
|