ormedGroup function
- @isTestGroup
- String description,
- void body(
- DataSource dataSource
- OrmedTestConfig? config,
- DataSource? dataSource,
- List<
Migration> ? migrations, - DatabaseRefreshStrategy? refreshStrategy,
- String? testOn,
- Timeout? timeout,
- dynamic skip,
- dynamic tags,
- Map<
String, dynamic> ? onPlatform, - int? retry,
Runs a test group with database isolation.
Groups related tests that share a common database setup. Every group gets its own unique DataSource (and thus a unique database) for true concurrency.
Use ormedGroup when you have multiple tests that operate on the same schema and you want to avoid the overhead of creating a fresh database for every single test.
ormedGroup('User tests', (db) {
ormedTest('creates a user', (db) async {
// ...
});
});
Pass config from setUpOrmed for explicit manager association:
final config = setUpOrmed(dataSource: harness.dataSource, ...);
ormedGroup('User tests', (db) { ... }, config: config);
Implementation
@isTestGroup
void ormedGroup(
String description,
void Function(DataSource dataSource) body, {
OrmedTestConfig? config,
DataSource? dataSource, // Optional override
List<Migration>? migrations, // Optional override
DatabaseRefreshStrategy? refreshStrategy,
String? testOn,
Timeout? timeout,
dynamic skip,
dynamic tags,
Map<String, dynamic>? onPlatform,
int? retry,
}) {
group(
description,
() {
// Resolve the manager to use
late final TestDatabaseManager manager;
late final OrmedTestConfig? resolvedConfig;
// Priority for finding manager:
// 1. Explicit config parameter
// 2. Explicit dataSource parameter
// 3. Parent group's context
// 4. Current Zone's config
// 5. Last registered config (legacy fallback)
// 6. Any available manager (last resort)
if (config != null) {
// Explicit config provided - use it
manager = config.manager;
resolvedConfig = config;
} else if (dataSource != null) {
// Custom dataSource provided - look up its manager or find matching one
resolvedConfig = null;
final dsName = dataSource.options.name;
// First, look for a manager registered for this dataSource
TestDatabaseManager? foundManager;
for (final entry in _managers.entries) {
if (entry.value.baseDataSource.options.name == dsName) {
foundManager = entry.value;
break;
}
}
if (foundManager == null) {
throw StateError(
'No manager found for DataSource "$dsName". '
'Call setUpOrmed() with this DataSource first.',
);
}
// Create a new manager with overrides if needed
if (migrations != null || refreshStrategy != null) {
manager = TestDatabaseManager(
baseDataSource: dataSource,
migrations: migrations ?? foundManager.migrations,
migrationDescriptors: foundManager.migrationDescriptors,
seeders: foundManager.seeders,
strategy: refreshStrategy ?? foundManager.strategy,
adapterFactory: foundManager.adapterFactory,
runMigrations: foundManager.runMigrations,
);
} else {
manager = foundManager;
}
} else if (_currentGroupContext?.config != null) {
// Use parent group's config
resolvedConfig = _currentGroupContext!.config;
manager = resolvedConfig!.manager;
} else if (_currentGroupContext != null) {
// Use parent group's manager (no config)
resolvedConfig = null;
manager = _currentGroupContext!.manager;
} else if (_currentZoneConfig != null) {
// Use Zone-local config
resolvedConfig = _currentZoneConfig;
manager = resolvedConfig!.manager;
} else if (_lastRegisteredConfig != null) {
// Legacy fallback: use last registered config
resolvedConfig = _lastRegisteredConfig;
manager = resolvedConfig!.manager;
} else if (_managers.isNotEmpty) {
// Last resort: use any available manager
resolvedConfig = null;
manager = _managers.values.first;
// Log a warning - this shouldn't happen in well-structured tests
print(
'[ormed_test] Warning: No explicit config found for ormedGroup "$description". '
'Using first available manager. Consider passing config explicitly.',
);
} else {
throw StateError(
'No test manager available. Call setUpOrmed() in main() first, '
'or pass config parameter to ormedGroup.',
);
}
final strategy = refreshStrategy ?? manager.strategy;
final groupId = _generateGroupId();
// Every group gets its own unique DataSource for true concurrency.
// This ensures that tests in different groups (even in the same file)
// do not interfere with each other.
final groupDataSource = manager.createDataSource(groupId);
final context = _GroupContext(
manager,
strategy,
groupId,
config: resolvedConfig,
);
context.dataSource = groupDataSource;
runZoned(() {
if (dataSource != null) {
setUpAll(() async {
await manager.initialize();
});
}
// Provision the unique database for the group
setUpAll(() async {
await manager.provisionDatabase(groupDataSource);
});
tearDownAll(() async {
await manager.dropDatabase(groupDataSource);
});
if (strategy == DatabaseIsolationStrategy.migrateWithTransactions) {
setUp(() async {
await groupDataSource.beginTransaction();
groupDataSource.setAsDefault();
});
tearDown(() async {
await groupDataSource.rollback();
});
} else {
setUp(() async {
final ds = groupDataSource;
final schemaManager = manager.getSchemaManager(ds);
if (schemaManager != null &&
strategy == DatabaseIsolationStrategy.truncate) {
// Fast path: truncate tables
await schemaManager.truncateAll();
} else if (strategy == DatabaseIsolationStrategy.recreate) {
// Slow path: full reset
if (schemaManager != null) {
await schemaManager.reset();
} else {
await manager.migrate(ds);
}
}
ds.setAsDefault();
});
}
// Execute body to define tests
body(groupDataSource);
}, zoneValues: {_groupContextKey: context});
},
testOn: testOn,
timeout: timeout,
skip: skip,
tags: tags,
onPlatform: onPlatform,
retry: retry,
);
}