Setting up basic API Structure
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
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');
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user