test_responses.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. """
  2. Tests for the responses plugin.
  3. Tests the real responses hook with an actual URL to verify
  4. network response capture.
  5. """
  6. import json
  7. import shutil
  8. import subprocess
  9. import sys
  10. import tempfile
  11. import time
  12. from pathlib import Path
  13. from django.test import TestCase
  14. # Import chrome test helpers
  15. sys.path.insert(0, str(Path(__file__).parent.parent.parent / 'chrome' / 'tests'))
  16. from chrome_test_helpers import (
  17. chrome_session,
  18. CHROME_NAVIGATE_HOOK,
  19. get_plugin_dir,
  20. get_hook_script,
  21. )
  22. # Get the path to the responses hook
  23. PLUGIN_DIR = get_plugin_dir(__file__)
  24. RESPONSES_HOOK = get_hook_script(PLUGIN_DIR, 'on_Snapshot__*_responses.*')
  25. class TestResponsesPlugin(TestCase):
  26. """Test the responses plugin."""
  27. def test_responses_hook_exists(self):
  28. """Responses hook script should exist."""
  29. self.assertIsNotNone(RESPONSES_HOOK, "Responses hook not found in plugin directory")
  30. self.assertTrue(RESPONSES_HOOK.exists(), f"Hook not found: {RESPONSES_HOOK}")
  31. class TestResponsesWithChrome(TestCase):
  32. """Integration tests for responses plugin with Chrome."""
  33. def setUp(self):
  34. """Set up test environment."""
  35. self.temp_dir = Path(tempfile.mkdtemp())
  36. def tearDown(self):
  37. """Clean up."""
  38. shutil.rmtree(self.temp_dir, ignore_errors=True)
  39. def test_responses_captures_network_responses(self):
  40. """Responses hook should capture network responses from page load."""
  41. test_url = 'https://example.com'
  42. snapshot_id = 'test-responses-snapshot'
  43. with chrome_session(
  44. self.temp_dir,
  45. crawl_id='test-responses-crawl',
  46. snapshot_id=snapshot_id,
  47. test_url=test_url,
  48. navigate=False,
  49. timeout=30,
  50. ) as (chrome_process, chrome_pid, snapshot_chrome_dir, env):
  51. responses_dir = snapshot_chrome_dir.parent / 'responses'
  52. responses_dir.mkdir(exist_ok=True)
  53. # Run responses hook with the active Chrome session (background hook)
  54. result = subprocess.Popen(
  55. ['node', str(RESPONSES_HOOK), f'--url={test_url}', f'--snapshot-id={snapshot_id}'],
  56. cwd=str(responses_dir),
  57. stdout=subprocess.PIPE,
  58. stderr=subprocess.PIPE,
  59. text=True,
  60. env=env
  61. )
  62. nav_result = subprocess.run(
  63. ['node', str(CHROME_NAVIGATE_HOOK), f'--url={test_url}', f'--snapshot-id={snapshot_id}'],
  64. cwd=str(snapshot_chrome_dir),
  65. capture_output=True,
  66. text=True,
  67. timeout=120,
  68. env=env
  69. )
  70. self.assertEqual(nav_result.returncode, 0, f"Navigation failed: {nav_result.stderr}")
  71. # Check for output directory and index file
  72. index_output = responses_dir / 'index.jsonl'
  73. # Wait briefly for background hook to write output
  74. for _ in range(30):
  75. if index_output.exists() and index_output.stat().st_size > 0:
  76. break
  77. time.sleep(1)
  78. # Verify hook ran (may keep running waiting for cleanup signal)
  79. if result.poll() is None:
  80. result.terminate()
  81. try:
  82. stdout, stderr = result.communicate(timeout=5)
  83. except subprocess.TimeoutExpired:
  84. result.kill()
  85. stdout, stderr = result.communicate()
  86. else:
  87. stdout, stderr = result.communicate()
  88. self.assertNotIn('Traceback', stderr)
  89. # If index file exists, verify it's valid JSONL
  90. if index_output.exists():
  91. with open(index_output) as f:
  92. content = f.read().strip()
  93. self.assertTrue(content, "Responses output should not be empty")
  94. for line in content.split('\n'):
  95. if line.strip():
  96. try:
  97. record = json.loads(line)
  98. # Verify structure
  99. self.assertIn('url', record)
  100. self.assertIn('resourceType', record)
  101. except json.JSONDecodeError:
  102. pass # Some lines may be incomplete
  103. if __name__ == '__main__':
  104. pytest.main([__file__, '-v'])