#!/usr/bin/env dart
/// App harness for server-pattern e2e tests.
///
/// This script spawns the SUT app and registers handlers per fixture,
/// returning expected responses. It's driven by the test setUpAll.
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:{{ pkg_name }}/{{ pkg_name }}.dart';
import 'package:{{ pkg_name }}/src/{{ bridge_module }}/frb_generated.dart' show RustLib;
// Load fixtures from the JSON payload.
// The fixtures dict contains per-fixture data with handler route, method, body_schema, etc.
const String _FIXTURES_JSON = r'''{{ fixtures_json }}''';
Future<void> main() async {
await RustLib.init();
final fixtures = jsonDecode(_FIXTURES_JSON) as Map<String, dynamic>? ?? {};
// Create and configure the app.
final app = App();
// Register a handler for each fixture.
for (final MapEntry<String, dynamic> entry in fixtures.entries) {
final fixtureId = entry.key;
final fixture = entry.value as Map<String, dynamic>? ?? {};
final http = fixture['http'] as Map<String, dynamic>?;
if (http == null) continue;
final handler = http['handler'] as Map<String, dynamic>? ?? {};
final route = handler['route'] as String? ?? '/';
final methodStr = (handler['method'] as String? ?? 'GET').toUpperCase();
final bodySchema = handler['body_schema'] as String?;
final expected = http['expected_response'] as Map<String, dynamic>? ?? {};
final expectedStatus = expected['status_code'] as int? ?? 200;
final expectedBody = expected['body'];
final expectedHeaders = (expected['headers'] as Map<String, dynamic>? ?? {}).cast<String, String>();
// Build handler function that returns the expected response.
String Function(String) makeHandler(int status, dynamic body, Map<String, String> headers) {
return (String _requestJson) {
// Return the expected response as JSON with status_code, body, and headers.
return jsonEncode({
'status_code': status,
'body': body,
'headers': headers,
});
};
}
// Register the handler at /fixtures/<fixture_id>{route}
final fullRoute = '/fixtures/$fixtureId$route';
// Convert method string to Method enum.
final methodEnum = _methodFromString(methodStr);
if (methodEnum == null) continue;
// Build the RouteBuilder with the path, method, and optional body schema.
var builder = await RouteBuilder.newInstance(method: methodEnum, path: fullRoute);
if (bodySchema != null && bodySchema.isNotEmpty) {
builder = await builder.requestSchemaJson(bodySchema);
}
// Register the route with the handler.
app.route(
builder,
makeHandler(expectedStatus, expectedBody, expectedHeaders),
);
}
// Bind and start the server on port 8008.
const host = '127.0.0.1';
const port = 8008;
// Print the SUT_URL so the test harness knows we're listening.
print('SUT_URL=http://$host:$port');
// Run the app (blocks until shutdown).
await app.run();
}
/// Convert HTTP method string (e.g., "GET", "POST") to Method enum.
Method? _methodFromString(String methodStr) {
switch (methodStr) {
case 'GET':
return Method.get_;
case 'POST':
return Method.post;
case 'PUT':
return Method.put;
case 'DELETE':
return Method.delete;
case 'PATCH':
return Method.patch;
case 'HEAD':
return Method.head;
case 'OPTIONS':
return Method.options;
case 'CONNECT':
return Method.connect;
case 'TRACE':
return Method.trace;
default:
return null;
}
}