diff --git a/tests/integration/test_activity_integration.py b/tests/integration/test_activity_integration.py index 80e9130..bb37e0e 100644 --- a/tests/integration/test_activity_integration.py +++ b/tests/integration/test_activity_integration.py @@ -116,37 +116,42 @@ class TestActivityIntegration(unittest.TestCase): # Create minimal activity content activity_content = """ default_max_attempts_per_step: 3 -tokens_for_ai_rubric: "Test rubric" sections: - section_id: "section_1" title: "Test Section" steps: - step_id: "step_1" - type: "question" + title: "Question 1" question: "What is 2+2?" + tokens_for_ai: "Categorize as 'correct' if answer is 4 or four, otherwise 'incorrect'" buckets: - - bucket_name: "correct" - bucket_criteria: "Answer is 4" - - bucket_name: "incorrect" - bucket_criteria: "Wrong answer" + - correct + - incorrect transitions: correct: - ai_feedback: - tokens_for_ai: "Provide encouragement" - next_section_id: "section_1" - next_step_id: "step_2" + content_blocks: + - "Great job!" + next_section_and_step: "section_1:step_2" incorrect: - ai_feedback: - tokens_for_ai: "Try again" - next_section_id: "section_1" - next_step_id: "step_1" + content_blocks: + - "Try again!" + counts_as_attempt: true + next_section_and_step: "section_1:step_1" - step_id: "step_2" - type: "question" + title: "Question 2" question: "What is 3+3?" + tokens_for_ai: "Categorize as 'correct' if answer is 6 or six, otherwise 'incorrect'" buckets: - - bucket_name: "correct" - bucket_criteria: "Answer is 6" + - correct + - incorrect + transitions: + correct: + content_blocks: + - "Excellent!" + incorrect: + content_blocks: + - "Not quite!" """ # Write to research directory with tempfile.NamedTemporaryFile( @@ -364,24 +369,32 @@ script_result = metadata['counter'] from models import ActivityState import activity - # Create activity with multiple info steps before question + # Create activity with multiple content-only steps before question activity_content = """ default_max_attempts_per_step: 3 sections: - section_id: "intro" + title: "Introduction" steps: - step_id: "info_1" - type: "info" - display_text: "Welcome!" + title: "Welcome" + content_blocks: + - "Welcome!" - step_id: "info_2" - type: "info" - display_text: "Let's begin" + title: "Let's Begin" + content_blocks: + - "Let's begin" - step_id: "question_1" - type: "question" + title: "Question" question: "Ready?" + tokens_for_ai: "Categorize as 'yes' for any response" buckets: - - bucket_name: "yes" + - yes + transitions: + yes: + content_blocks: + - "Great!" """ with tempfile.NamedTemporaryFile( mode="w", suffix=".yaml", dir="research", delete=False diff --git a/tests/integration/test_activity_processing.py b/tests/integration/test_activity_processing.py index 78da2d3..497e3a0 100644 --- a/tests/integration/test_activity_processing.py +++ b/tests/integration/test_activity_processing.py @@ -31,6 +31,7 @@ with patch.dict( }, ): import app + import activity class MockActivityState: @@ -178,7 +179,7 @@ script_result = { # Execute the processing script if transition.get("run_processing_script", False): - result = app.execute_processing_script( + result = activity.execute_processing_script( activity_state.dict_metadata, script_step["processing_script"] ) @@ -236,7 +237,7 @@ script_result = { temp_metadata["user_response"] = user_response # Execute pre-script - pre_result = app.execute_processing_script( + pre_result = activity.execute_processing_script( temp_metadata, pre_script_step["pre_script"] ) @@ -334,7 +335,7 @@ script_result = { navigation_path = [] for _ in range(10): # Prevent infinite loop - next_section, next_step = app.get_next_step( + next_section, next_step = activity.get_next_step( multi_section_activity, current_section, current_step ) @@ -371,9 +372,9 @@ script_result = { ) with patch.object( - app, "provide_feedback", return_value=mock_feedback + activity, "provide_feedback", return_value=mock_feedback ) as mock_func: - result = app.provide_feedback( + result = activity.provide_feedback( transition_with_feedback, "correct", "What is 2+2?", @@ -403,7 +404,7 @@ if True # Should handle syntax errors gracefully with self.assertRaises(SyntaxError): - app.execute_processing_script(metadata, invalid_script) + activity.execute_processing_script(metadata, invalid_script) def test_processing_script_runtime_error(self): """Test handling of runtime errors in processing scripts""" @@ -416,15 +417,15 @@ script_result = {'status': 'error'} # Should handle runtime errors gracefully with self.assertRaises(ZeroDivisionError): - app.execute_processing_script(metadata, runtime_error_script) + activity.execute_processing_script(metadata, runtime_error_script) def test_missing_activity_content(self): """Test handling of missing activity content""" - with patch.object(app, "get_activity_content") as mock_get_content: + with patch.object(activity, "get_activity_content") as mock_get_content: mock_get_content.side_effect = FileNotFoundError("Activity file not found") with self.assertRaises(FileNotFoundError): - app.get_activity_content("nonexistent_activity.yaml") + activity.get_activity_content("nonexistent_activity.yaml") mock_get_content.assert_called_once_with("nonexistent_activity.yaml") @@ -448,7 +449,7 @@ script_result = {'status': 'error'} f.write(malformed_yaml) with self.assertRaises(yaml.YAMLError): # YAML parsing error - app.get_activity_content("research/malformed.yaml") + activity.get_activity_content("research/malformed.yaml") finally: os.unlink(temp_file) diff --git a/tests/integration/test_app_activity_functions.py b/tests/integration/test_app_activity_functions.py index 313492f..c908e9e 100644 --- a/tests/integration/test_app_activity_functions.py +++ b/tests/integration/test_app_activity_functions.py @@ -23,6 +23,7 @@ from flask_socketio import SocketIO # Import the main application import app +import activity from models import db, Room, ActivityState, Message @@ -60,6 +61,9 @@ class TestFlaskAppActivityFunctions(unittest.TestCase): # Store original socketio for cleanup self.original_socketio = app.socketio + # Initialize activity module with app's socketio and db + activity.init_activity_module(app.socketio, db) + def tearDown(self): """Clean up test environment""" db.session.remove() @@ -116,7 +120,7 @@ sections: try: # Test the actual get_activity_content function - result = app.get_activity_content(f"research/{activity_file}") + result = activity.get_activity_content(f"research/{activity_file}") # Verify structure self.assertEqual(result["title"], "Test Activity") @@ -169,7 +173,7 @@ sections: )() # Test start_activity function - app.start_activity("test_room", f"research/{activity_file}", "testuser") + activity.start_activity("test_room", f"research/{activity_file}", "testuser") # Verify activity state was created in database activity_state = ActivityState.query.filter_by( @@ -244,7 +248,7 @@ sections: db.session.commit() # Test handling a correct response - app.handle_activity_response("test_room", "10", "testuser") + activity.handle_activity_response("test_room", "10", "testuser") # Refresh activity state from database db.session.refresh(activity_state) @@ -305,7 +309,7 @@ sections: db.session.commit() # Test display_activity_metadata function - app.display_activity_metadata("test_room", "testuser") + activity.display_activity_metadata("test_room", "testuser") # Verify that a message was emitted self.assertTrue(len(emitted_messages) > 0) @@ -367,7 +371,7 @@ sections: ) # Test cancel_activity function - app.cancel_activity("test_room", "testuser") + activity.cancel_activity("test_room", "testuser") # Verify activity was deleted from database self.assertIsNone( @@ -421,7 +425,7 @@ script_result = { } # Test the actual execute_processing_script function - result = app.execute_processing_script(metadata, script) + result = activity.execute_processing_script(metadata, script) # Verify script execution results self.assertEqual(result["status"], "success") @@ -459,21 +463,21 @@ script_result = { } # Test navigation within section - next_section, next_step = app.get_next_step( + next_section, next_step = activity.get_next_step( activity_content, "section_1", "step_1" ) self.assertEqual(next_section["section_id"], "section_1") self.assertEqual(next_step["step_id"], "step_2") # Test navigation across sections - next_section, next_step = app.get_next_step( + next_section, next_step = activity.get_next_step( activity_content, "section_1", "step_3" ) self.assertEqual(next_section["section_id"], "section_2") self.assertEqual(next_step["step_id"], "step_1") # Test at end of activity - next_section, next_step = app.get_next_step( + next_section, next_step = activity.get_next_step( activity_content, "section_2", "step_2" ) self.assertIsNone(next_section) @@ -490,7 +494,7 @@ script_result = { ) # Test the actual categorization function - result = app.categorize_response(question, response, buckets, tokens_for_ai) + result = activity.categorize_response(question, response, buckets, tokens_for_ai) # Result should be either "correct", "incorrect", or an error message self.assertIsInstance(result, str) @@ -502,19 +506,19 @@ script_result = { """Test text translation functionality""" # Test English bypass english_text = "Hello, world!" - result = app.translate_text(english_text, "English") + result = activity.translate_text(english_text, "English") self.assertEqual(result, english_text) # Test case insensitive - result = app.translate_text(english_text, "english") + result = activity.translate_text(english_text, "english") self.assertEqual(result, english_text) # Test with compound language - result = app.translate_text(english_text, "English please") + result = activity.translate_text(english_text, "English please") self.assertEqual(result, english_text) # Test other language (will use AI endpoint if available) - result = app.translate_text("Hello", "Spanish") + result = activity.translate_text("Hello", "Spanish") self.assertIsInstance(result, str) # Should return some string result