cyberhybridhub/server/test/integration/spelling_only_panel_test.dart
nathanAndrinoid a7c370b743
Some checks failed
Admin portal tests / test (push) Has been cancelled
Fix database connection pooling and UI question filtering
- Replaced single Postgres Connection with Pool across the server to prevent runTx locking
- Added _filterForEnabledSources to client's _fetchUnansweredForPanel to strictly enforce local configuration

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-05 22:04:06 +00:00

149 lines
4.6 KiB
Dart

@Tags(<String>['integration', 'postgres'])
library;
import 'package:cyberhybridhub_server/question_dispatcher.dart';
import 'package:cyberhybridhub_server/questions_db.dart';
import 'package:test/test.dart';
import '../helpers/test_db.dart';
void main() {
TestDb? testDb;
setUpAll(() async {
testDb = await TestDb.open();
});
tearDown(() async {
if (testDb != null) {
await testDb!.truncateTradingTables();
}
});
tearDownAll(() async {
await testDb?.close();
});
test(
'listPanelQuestions excludes market when market_history enabled at ratio 0',
() async {
if (testDb == null) {
markTestSkipped('Set DATABASE_URL or TEST_DATABASE_URL for integration tests');
return;
}
// The critical scenario: user sets spelling=100%, market stays enabled but
// ratio=0. A stale market question is already in the DB. The dispatcher
// must never serve it.
const String uid = 'spelling-100-market-0-panel-uid';
await testDb!.seedUser(uid);
await testDb!.questionSourcePreferencesDb.save(
uid,
<Map<String, dynamic>>[
<String, dynamic>{'id': 'market_history', 'enabled': true, 'ratio': 0},
<String, dynamic>{'id': 'spelling', 'enabled': true, 'ratio': 100},
],
);
await testDb!.questionsDb.createQuestion(
assignedUserId: uid,
questionText: 'Stale market question',
correctAnswer: 10,
sourceTag: 'market_history:prospective',
pipelineKey: 'trading',
);
final QuestionDispatcher dispatcher = testDb!.questionDispatcher();
final List<Map<String, dynamic>> panel =
await dispatcher.listPanelQuestions(uid);
expect(panel, isNotEmpty);
for (final Map<String, dynamic> payload in panel) {
expect(payload['sourceId'], isNot('market_history'));
}
expect(panel.first['sourceId'], 'spelling');
expect(panel.first['presentation'], 'spelling_word');
});
test('nextQuestionAfterAnswer never returns market when spelling is 100%',
() async {
if (testDb == null) {
markTestSkipped('Set DATABASE_URL or TEST_DATABASE_URL for integration tests');
return;
}
const String uid = 'spelling-100-next-answer-uid';
await testDb!.seedUser(uid);
await testDb!.questionSourcePreferencesDb.save(
uid,
<Map<String, dynamic>>[
<String, dynamic>{'id': 'market_history', 'enabled': true, 'ratio': 0},
<String, dynamic>{'id': 'spelling', 'enabled': true, 'ratio': 100},
],
);
// Seed a stale market question that should never surface.
await testDb!.questionsDb.createQuestion(
assignedUserId: uid,
questionText: 'Old market question',
correctAnswer: 5,
sourceTag: 'market_history:prospective',
pipelineKey: 'trading',
);
final QuestionDispatcher dispatcher = testDb!.questionDispatcher();
// Simulate the context of "just answered a spelling question".
final Map<String, dynamic> fakeAnswered = <String, dynamic>{
'sourceTag': 'spelling:word_quiz',
'pipelineKey': 'spelling',
'pipelineStep': 'spelling_word_quiz',
};
final Map<String, dynamic>? next = await dispatcher.nextQuestionAfterAnswer(
firebaseUid: uid,
answeredQuestion: fakeAnswered,
);
expect(next, isNotNull);
expect(next!['sourceId'], isNot('market_history'));
expect(next['sourceId'], 'spelling');
});
test('listPanelQuestions excludes market when market_history disabled', () async {
if (testDb == null) {
markTestSkipped('Set DATABASE_URL or TEST_DATABASE_URL for integration tests');
return;
}
const String uid = 'spelling-only-panel-uid';
await testDb!.seedUser(uid);
await testDb!.questionSourcePreferencesDb.save(
uid,
<Map<String, dynamic>>[
<String, dynamic>{'id': 'market_history', 'enabled': false, 'ratio': 0},
<String, dynamic>{'id': 'spelling', 'enabled': true, 'ratio': 100},
],
);
await testDb!.questionsDb.createQuestion(
assignedUserId: uid,
questionText: 'Stale market question',
correctAnswer: 10,
sourceTag: 'market_history:prospective',
pipelineKey: 'trading',
);
final QuestionDispatcher dispatcher = testDb!.questionDispatcher();
final List<Map<String, dynamic>> panel =
await dispatcher.listPanelQuestions(uid);
expect(panel, isNotEmpty);
for (final Map<String, dynamic> payload in panel) {
expect(payload['sourceId'], isNot('market_history'));
}
expect(panel.first['sourceId'], 'spelling');
expect(panel.first['presentation'], 'spelling_word');
});
}