Files
potato-mesh/app/test/main_utilities_test.dart
T
l5y fec649a159 app: add utility coverage tests for main.dart (#552)
* Add utility coverage tests for main.dart

* Add channel names to message sorting tests

* Fix MeshMessage sort test construction

* chore: run dart formatter
2025-12-15 11:03:51 +01:00

129 lines
3.7 KiB
Dart

// Copyright © 2025-26 l5yth & contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:potato_mesh_reader/main.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
test('BootstrapProgress renders stage, counts, and detail', () {
const progress = BootstrapProgress(
stage: 'Downloading',
current: 2,
total: 5,
detail: 'instances',
);
expect(progress.label, 'Downloading 2/5 • instances');
const fallback = BootstrapProgress(stage: 'Starting');
expect(fallback.label, 'Starting');
});
test('InstanceVersion summary prefers populated fields', () {
const populated = InstanceVersion(
name: 'BerlinMesh',
channel: '#MediumFast',
frequency: '868MHz',
instanceDomain: 'potatomesh.net',
);
expect(populated.summary, 'BerlinMesh · #MediumFast · 868MHz');
const minimal = InstanceVersion(
name: '',
channel: null,
frequency: null,
instanceDomain: null,
);
expect(minimal.summary, 'Unknown');
});
test('sortMessagesByRxTime keeps unknown timestamps in place', () {
MeshMessage buildMessage({
required int id,
required String text,
required String rxIso,
DateTime? rxTime,
}) {
return MeshMessage(
id: id,
rxTime: rxTime,
rxIso: rxIso,
fromId: '!$id',
nodeId: '!$id',
toId: '^',
channelName: '#general',
channel: 1,
portnum: 'TEXT',
text: text,
rssi: -50,
snr: 1.0,
hopLimit: 1,
);
}
final withTime = buildMessage(
id: 2,
rxTime: DateTime.utc(2024, 1, 1, 12, 1),
rxIso: '2024-01-01T12:01:00Z',
text: 'timed',
);
final withoutTime = buildMessage(
id: 1,
rxTime: null,
rxIso: 'unknown',
text: 'unknown',
);
final laterTime = buildMessage(
id: 3,
rxTime: DateTime.utc(2024, 1, 1, 12, 5),
rxIso: '2024-01-01T12:05:00Z',
text: 'later',
);
final sorted = sortMessagesByRxTime([withoutTime, laterTime, withTime]);
expect(sorted.first.id, withoutTime.id,
reason: 'messages without rxTime should retain position');
expect(sorted[1].id, withTime.id,
reason: 'messages with timestamps should be ordered chronologically');
expect(sorted.last.id, laterTime.id);
});
testWidgets('LoadingScreen displays progress label and icon', (tester) async {
const screen = LoadingScreen(
progress: BootstrapProgress(stage: 'Fetching'),
);
await tester.pumpWidget(const MaterialApp(home: screen));
expect(find.byType(CircularProgressIndicator), findsOneWidget);
expect(find.text('Fetching'), findsOneWidget);
expect(find.bySemanticsLabel('PotatoMesh'), findsOneWidget);
});
testWidgets('LoadingScreen surfaces errors', (tester) async {
const screen = LoadingScreen(
progress: BootstrapProgress(stage: 'Loading'),
error: 'boom',
);
await tester.pumpWidget(const MaterialApp(home: screen));
expect(find.textContaining('Failed to load: boom'), findsOneWidget);
});
}