166 lines
5.2 KiB
Dart
166 lines
5.2 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'package:ac_web/Api/Api.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:http/http.dart' as http;
|
|
import 'package:http/testing.dart';
|
|
|
|
const ApiConfig testConfig = ApiConfig(host: 'api.local', port: 5000, basePath: 'api');
|
|
|
|
AcApi apiReturning(String body, {int statusCode = 200, void Function(Uri uri)? onRequest}) {
|
|
final client = MockClient((request) async {
|
|
onRequest?.call(request.url);
|
|
return http.Response(body, statusCode, headers: {'content-type': 'application/json'});
|
|
});
|
|
return AcApi(config: testConfig, httpClient: client);
|
|
}
|
|
|
|
void main() {
|
|
group('ApiConfig', () {
|
|
test('builds http uris including base path and query', () {
|
|
final uri = testConfig.buildUri('agents', {'onlyOnline': true, 'skip': null});
|
|
|
|
expect(uri.toString(), 'http://api.local:5000/api/agents?onlyOnline=true');
|
|
});
|
|
});
|
|
|
|
group('AgentsService', () {
|
|
test('parses agents with enums as names and nested tasks', () async {
|
|
Uri? requested;
|
|
final api = apiReturning(
|
|
jsonEncode([
|
|
{
|
|
'name': 'Ada',
|
|
'type': 'Developer',
|
|
'lastSeen': '2026-08-28T12:00:00Z',
|
|
'status': 'Working',
|
|
'tasks': [
|
|
{'name': 'Implement api layer', 'status': 'InProgress', 'progress': 42},
|
|
],
|
|
},
|
|
]),
|
|
onRequest: (uri) => requested = uri,
|
|
);
|
|
|
|
final agents = await api.agents.getAgents();
|
|
|
|
expect(requested.toString(), 'http://api.local:5000/api/agents');
|
|
expect(agents, hasLength(1));
|
|
expect(agents.single.name, 'Ada');
|
|
expect(agents.single.type, EAgentType.developer);
|
|
expect(agents.single.status, EAgentStatus.working);
|
|
expect(agents.single.lastSeen.isUtc, isTrue);
|
|
expect(agents.single.tasks.single.name, 'Implement api layer');
|
|
expect(agents.single.tasks.single.progress, 42);
|
|
});
|
|
|
|
test('parses numeric enums and falls back to unknown', () async {
|
|
final api = apiReturning(
|
|
jsonEncode([
|
|
{
|
|
'Name': 'Numeric',
|
|
'Type': 1,
|
|
'LastSeen': '2026-08-28T12:00:00Z',
|
|
'Status': 2,
|
|
'Tasks': [],
|
|
},
|
|
{
|
|
'Name': 'Future',
|
|
'Type': 'SomethingNew',
|
|
'LastSeen': '2026-08-28T12:00:00Z',
|
|
'Status': 'AlsoNew',
|
|
'Tasks': [],
|
|
},
|
|
]),
|
|
);
|
|
|
|
final agents = await api.agents.getAgents();
|
|
|
|
expect(agents.first.type, EAgentType.tester);
|
|
expect(agents.first.status, EAgentStatus.working);
|
|
expect(agents.first.tasks, isEmpty);
|
|
expect(agents.last.type, EAgentType.unknown);
|
|
expect(agents.last.status, EAgentStatus.unknown);
|
|
});
|
|
|
|
test('throws ApiParsingException on a malformed payload', () async {
|
|
final api = apiReturning(jsonEncode([{'Type': 'Developer'}]));
|
|
|
|
expect(() => api.agents.getAgents(), throwsA(isA<ApiParsingException>()));
|
|
});
|
|
});
|
|
|
|
group('ReportsService', () {
|
|
test('returns reports sorted newest first', () async {
|
|
final api = apiReturning(
|
|
jsonEncode([
|
|
{
|
|
'Id': 'older',
|
|
'Author': 'Ada',
|
|
'Timestamp': '2026-08-20T10:00:00Z',
|
|
'Type': 'LOG',
|
|
'Text': 'first',
|
|
},
|
|
{
|
|
'Id': 'newer',
|
|
'Author': 'Grace',
|
|
'Timestamp': '2026-08-27T10:00:00Z',
|
|
'Type': 'CODE_REVIEW',
|
|
'Text': 'second',
|
|
},
|
|
]),
|
|
);
|
|
|
|
final reports = await api.reports.getReports();
|
|
|
|
expect(reports.map((report) => report.id), ['newer', 'older']);
|
|
expect(reports.first.author, 'Grace');
|
|
expect(reports.first.type, EReportType.codeReview);
|
|
});
|
|
|
|
test('maps error status codes onto ApiHttpException', () async {
|
|
final api = apiReturning('{"error":"boom"}', statusCode: 500);
|
|
|
|
await expectLater(
|
|
api.reports.getReports(),
|
|
throwsA(isA<ApiHttpException>().having((error) => error.isServerError, 'isServerError', isTrue)),
|
|
);
|
|
});
|
|
|
|
test('maps transport failures onto ApiNetworkException', () async {
|
|
final api = AcApi(
|
|
config: testConfig,
|
|
httpClient: MockClient((request) async => throw http.ClientException('offline')),
|
|
);
|
|
|
|
await expectLater(api.reports.getReports(), throwsA(isA<ApiNetworkException>()));
|
|
});
|
|
|
|
test('treats an empty body as an empty list', () async {
|
|
final api = apiReturning('', statusCode: 204);
|
|
|
|
expect(await api.reports.getReports(), isEmpty);
|
|
});
|
|
});
|
|
|
|
group('Dto round trip', () {
|
|
test('agent survives toJson/fromJson', () {
|
|
final original = AgentDto(
|
|
name: 'Ada',
|
|
type: EAgentType.reviewer,
|
|
lastSeen: DateTime.utc(2026, 8, 28, 12),
|
|
tasks: const [AgentTaskDto(name: 'Review', status: 'Open')],
|
|
status: EAgentStatus.idle,
|
|
);
|
|
|
|
final restored = AgentDto.fromJson(original.toJson());
|
|
|
|
expect(restored.name, original.name);
|
|
expect(restored.type, original.type);
|
|
expect(restored.status, original.status);
|
|
expect(restored.lastSeen, original.lastSeen);
|
|
expect(restored.tasks.single.name, 'Review');
|
|
});
|
|
});
|
|
}
|