From e5efb541c40145a0b44722f151945e4eb07b1ef1 Mon Sep 17 00:00:00 2001 From: Bryce Date: Sun, 3 Aug 2025 21:45:44 -0700 Subject: [PATCH] improvements on tests --- QWEN.md | 2 + app/routes.py | 3 +- requirements.txt | 4 +- tests/test_routes.py | 242 ++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 247 insertions(+), 4 deletions(-) diff --git a/QWEN.md b/QWEN.md index 10c92a0..6907602 100644 --- a/QWEN.md +++ b/QWEN.md @@ -17,3 +17,5 @@ Here are special rules you must follow: 3. modals can be closed by triggering a close-modal event anywhere in the dom. 4. validation is done server-side. On modals, an error should cause the button to shake, and the invalid fields to be highlighted in red using normal daisyui paradigms. When relevant, there should be a notification banner inside the dialog-box to show the details of the error. 5. When validation is done outside of a modal, it should cause a notification banner with the details. +6. Testing is done with pytest. +7. Testing is done with beautifulsoup4 diff --git a/app/routes.py b/app/routes.py index b2dbdae..90395d9 100644 --- a/app/routes.py +++ b/app/routes.py @@ -200,5 +200,4 @@ def update_folder(folder_id): response = make_response(render_template('partials/folder_modal.html', folder=folder, errors=errors, name=name, rule_text=rule_text, priority=priority)) response.headers['HX-Retarget'] = '#folder-modal' response.headers['HX-Reswap'] = 'outerHTML' - return response - + return response \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 907c5d4..6b6d5d3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,6 @@ Flask==2.3.2 Flask-SQLAlchemy==3.0.5 psycopg2-binary==2.9.7 -pytest==7.4.0 \ No newline at end of file +pytest==7.4.0 +beautifulsoup4==4.13.4 +Flask-Migrate==4.1.0 diff --git a/tests/test_routes.py b/tests/test_routes.py index 0ea9174..fa62420 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -1,6 +1,8 @@ import pytest from app.models import User, Folder +from app.routes import MOCK_USER_ID import uuid +from bs4 import BeautifulSoup def test_index_route(client, app, mock_user): response = client.get('/') @@ -25,4 +27,242 @@ def test_add_folder_route(client, mock_user): # Verify that the number of folders has increased final_folder_count = Folder.query.count() - assert final_folder_count > initial_folder_count \ No newline at end of file + assert final_folder_count > initial_folder_count + +# Validation failure tests +def test_add_folder_validation_failure_empty_name(client, mock_user): + """Test validation failure when folder name is empty.""" + response = client.post('/api/folders', + data={'name': '', 'rule_text': 'Test rule something ok yes'}, + content_type='application/x-www-form-urlencoded') + + assert response.status_code == 200 + # Check that the specific error message is present + assert b'Folder name is required' in response.data + # Check that the input field has the error class + assert b'input-error' in response.data + +def test_add_folder_validation_failure_short_name(client, mock_user): + """Test validation failure when folder name is too short.""" + response = client.post('/api/folders', + data={'name': 'ab', 'rule_text': 'Test rule something ok yes'}, + content_type='application/x-www-form-urlencoded') + + assert response.status_code == 200 + assert b'Folder name must be at least 3 characters' in response.data + +def test_add_folder_validation_failure_long_name(client, mock_user): + """Test validation failure when folder name is too long.""" + long_name = 'a' * 51 + response = client.post('/api/folders', + data={'name': long_name, 'rule_text': 'Test rule something ok yes'}, + content_type='application/x-www-form-urlencoded') + + assert response.status_code == 200 + assert b'Folder name must be less than 50 characters' in response.data + +def test_add_folder_validation_failure_empty_rule(client, mock_user): + """Test validation failure when rule text is empty.""" + response = client.post('/api/folders', + data={'name': 'Test Folder', 'rule_text': ''}, + content_type='application/x-www-form-urlencoded') + + assert response.status_code == 200 + assert b'Rule text is required' in response.data + +def test_add_folder_validation_failure_short_rule(client, mock_user): + """Test validation failure when rule text is too short.""" + response = client.post('/api/folders', + data={'name': 'Test Folder', 'rule_text': 'short'}, + content_type='application/x-www-form-urlencoded') + + assert response.status_code == 200 + assert b'Rule text must be at least 10 characters' in response.data + +def test_add_folder_validation_failure_long_rule(client, mock_user): + """Test validation failure when rule text is too long.""" + long_rule = 'a' * 201 + response = client.post('/api/folders', + data={'name': 'Test Folder', 'rule_text': long_rule}, + content_type='application/x-www-form-urlencoded') + + assert response.status_code == 200 + assert b'Rule text must be less than 200 characters' in response.data + +def test_add_folder_validation_multiple_errors(client, mock_user): + """Test validation failure with multiple errors.""" + response = client.post('/api/folders', + data={'name': 'ab', 'rule_text': 'short'}, + content_type='application/x-www-form-urlencoded') + + assert response.status_code == 200 + assert b'Folder name must be at least 3 characters' in response.data + assert b'Rule text must be at least 10 characters' in response.data + +# Edit folder validation failure tests +def test_edit_folder_validation_failure_empty_name(client, mock_folder): + """Test validation failure when folder name is empty during edit.""" + response = client.put(f'/api/folders/{mock_folder.id}', + data={'name': '', 'rule_text': 'Test rule something ok yes'}, + content_type='application/x-www-form-urlencoded') + + assert response.status_code == 200 + assert b'Folder name is required' in response.data + +def test_edit_folder_validation_failure_short_name(client, mock_folder): + """Test validation failure when folder name is too short during edit.""" + response = client.put(f'/api/folders/{mock_folder.id}', + data={'name': 'ab', 'rule_text': 'Test rule something ok yes'}, + content_type='application/x-www-form-urlencoded') + + assert response.status_code == 200 + assert b'Folder name must be at least 3 characters' in response.data + +def test_edit_folder_validation_failure_long_name(client, mock_folder): + """Test validation failure when folder name is too long during edit.""" + long_name = 'a' * 51 + response = client.put(f'/api/folders/{mock_folder.id}', + data={'name': long_name, 'rule_text': 'Test rule something ok yes'}, + content_type='application/x-www-form-urlencoded') + + assert response.status_code == 200 + assert b'Folder name must be less than 50 characters' in response.data + +def test_edit_folder_validation_failure_empty_rule(client, mock_folder): + """Test validation failure when rule text is empty during edit.""" + response = client.put(f'/api/folders/{mock_folder.id}', + data={'name': 'Test Folder', 'rule_text': ''}, + content_type='application/x-www-form-urlencoded') + + assert response.status_code == 200 + assert b'Rule text is required' in response.data + +def test_edit_folder_validation_failure_short_rule(client, mock_folder): + """Test validation failure when rule text is too short during edit.""" + response = client.put(f'/api/folders/{mock_folder.id}', + data={'name': 'Test Folder', 'rule_text': 'short'}, + content_type='application/x-www-form-urlencoded') + + assert response.status_code == 200 + assert b'Rule text must be at least 10 characters' in response.data + +def test_edit_folder_validation_failure_long_rule(client, mock_folder): + """Test validation failure when rule text is too long during edit.""" + long_rule = 'a' * 201 + response = client.put(f'/api/folders/{mock_folder.id}', + data={'name': 'Test Folder', 'rule_text': long_rule}, + content_type='application/x-www-form-urlencoded') + + assert response.status_code == 200 + assert b'Rule text must be less than 200 characters' in response.data + +def test_edit_folder_validation_multiple_errors(client, mock_folder): + """Test validation failure with multiple errors during edit.""" + response = client.put(f'/api/folders/{mock_folder.id}', + data={'name': 'ab', 'rule_text': 'short'}, + content_type='application/x-www-form-urlencoded') + + assert response.status_code == 200 + assert b'Folder name must be at least 3 characters' in response.data + assert b'Rule text must be at least 10 characters' in response.data + +# Dialog close tests +def test_add_folder_success_closes_dialog(client, mock_user): + """Test that successful folder creation triggers dialog close.""" + response = client.post('/api/folders', + data={'name': 'Test Folder', 'rule_text': 'Test rule something ok yes'}, + content_type='application/x-www-form-urlencoded') + + assert response.status_code == 201 + # Check for close-modal trigger in response headers + assert 'HX-Trigger' in response.headers + assert 'close-modal' in response.headers['HX-Trigger'] + +def test_edit_folder_success_closes_dialog(client, mock_folder): + """Test that successful folder update triggers dialog close.""" + response = client.put(f'/api/folders/{mock_folder.id}', + data={'name': 'Updated Folder', 'rule_text': 'Updated rule text'}, + content_type='application/x-www-form-urlencoded') + + assert response.status_code == 200 + # Check for close-modal trigger in response headers + assert 'HX-Trigger' in response.headers + assert 'close-modal' in response.headers['HX-Trigger'] + +# Content matching tests +def test_add_folder_content_matches_submission(client, mock_user): + """Test that submitted folder content matches what was sent.""" + test_name = 'Test Folder Content' + test_rule = 'Test rule content matching submission' + test_priority = '1' + + response = client.post('/api/folders', + data={'name': test_name, 'rule_text': test_rule, 'priority': test_priority}, + content_type='application/x-www-form-urlencoded') + + assert response.status_code == 201 + + # Verify the folder was created with correct content + created_folder = Folder.query.filter_by(name=test_name).first() + assert created_folder is not None + assert created_folder.name == test_name.strip() + assert created_folder.rule_text == test_rule.strip() + assert created_folder.priority == int(test_priority) + assert created_folder.user_id == MOCK_USER_ID + +def test_edit_folder_content_matches_submission(client, mock_folder): + """Test that updated folder content matches what was sent.""" + test_name = 'Updated Folder Content' + test_rule = 'Updated rule content matching submission' + test_priority = '-1' + + response = client.put(f'/api/folders/{mock_folder.id}', + data={'name': test_name, 'rule_text': test_rule, 'priority': test_priority}, + content_type='application/x-www-form-urlencoded') + + assert response.status_code == 200 + + # Verify the folder was updated with correct content + updated_folder = Folder.query.filter_by(id=mock_folder.id).first() + assert updated_folder is not None + assert updated_folder.name == test_name.strip() + assert updated_folder.rule_text == test_rule.strip() + assert updated_folder.priority == int(test_priority) + +def test_add_folder_content_whitespace_handling(client, mock_user): + """Test that whitespace is properly handled in submitted content.""" + test_name = ' Test Folder With Whitespace ' + test_rule = ' Test rule with whitespace around it ' + test_priority = '0' + + response = client.post('/api/folders', + data={'name': test_name, 'rule_text': test_rule, 'priority': test_priority}, + content_type='application/x-www-form-urlencoded') + + assert response.status_code == 201 + + # Verify the folder was created with properly trimmed content + created_folder = Folder.query.filter_by(name='Test Folder With Whitespace').first() + assert created_folder is not None + assert created_folder.name == 'Test Folder With Whitespace' # Should be trimmed + assert created_folder.rule_text == 'Test rule with whitespace around it' # Should be trimmed + assert created_folder.priority == int(test_priority) + +def test_edit_folder_content_whitespace_handling(client, mock_folder): + """Test that whitespace is properly handled in updated content.""" + test_name = ' Updated Folder With Whitespace ' + test_rule = ' Updated rule with whitespace around it ' + test_priority = '1' + + response = client.put(f'/api/folders/{mock_folder.id}', + data={'name': test_name, 'rule_text': test_rule, 'priority': test_priority}, + content_type='application/x-www-form-urlencoded') + + assert response.status_code == 200 + + # Verify the folder was updated with properly trimmed content + updated_folder = Folder.query.filter_by(id=mock_folder.id).first() + assert updated_folder is not None + assert updated_folder.name == 'Updated Folder With Whitespace' # Should be trimmed + assert updated_folder.rule_text == 'Updated rule with whitespace around it' # Should be trimmed + assert updated_folder.priority == int(test_priority) \ No newline at end of file