Files
AcWeb/ac_web/test/Api/ApiLayerTest.dart
T

166 lines
5.1 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': 'Info',
'Text': 'first',
},
{
'Id': 'newer',
'Author': 'Grace',
'Timestamp': '2026-08-27T10:00:00Z',
'Type': 'Warning',
'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, 'Warning');
});
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');
});
});
}