diff --git a/frontend/testing/unit/components/Background.test.tsx b/frontend/testing/unit/components/Background.test.tsx
new file mode 100644
index 000000000..088c1848c
--- /dev/null
+++ b/frontend/testing/unit/components/Background.test.tsx
@@ -0,0 +1,34 @@
+import React from 'react'
+import { render } from '@testing-library/react'
+import { describe, it, expect } from 'vitest'
+import Background from '../../../src/components/Background'
+
+describe('Background Component', () => {
+ it('renders without crashing with default props', () => {
+ const { container } = render(
)
+ const wrapper = container.querySelector('.background')
+ expect(wrapper).toBeInTheDocument()
+ expect(wrapper).toHaveClass('background--idle')
+ })
+
+ it('renders with different state props', () => {
+ const { container: activeContainer } = render(
)
+ expect(activeContainer.querySelector('.background')).toHaveClass('background--active')
+
+ const { container: errorContainer } = render(
)
+ expect(errorContainer.querySelector('.background')).toHaveClass('background--error')
+ })
+
+ it('asserts decorative container and layers are aria-hidden', () => {
+ const { container } = render(
)
+
+ // The main wrapper should be aria-hidden since it is decorative background
+ const wrapper = container.querySelector('.background')
+ expect(wrapper).toHaveAttribute('aria-hidden', 'true')
+
+ // Confirm that the decorative internal elements exist as well
+ expect(container.querySelector('.background-grid')).toBeInTheDocument()
+ expect(container.querySelector('.background-scan')).toBeInTheDocument()
+ expect(container.querySelector('.background-lines')).toBeInTheDocument()
+ })
+})
diff --git a/testing/backend/unit/test_tls_verification.py b/testing/backend/unit/test_tls_verification.py
index be8281d83..2b712d3ae 100644
--- a/testing/backend/unit/test_tls_verification.py
+++ b/testing/backend/unit/test_tls_verification.py
@@ -54,15 +54,23 @@ def test_env_override_true(self, monkeypatch):
class TestCrawlerVerifySsl:
@pytest.mark.asyncio
async def test_crawl_target_passes_verify_ssl(self):
+ async def mock_aiter_bytes():
+ yield b""
+
mock_response = MagicMock()
mock_response.text = ""
mock_response.url = "https://example.com/"
mock_response.status_code = 200
mock_response.headers = {}
mock_response.history = []
+ mock_response.aiter_bytes = mock_aiter_bytes
+
+ mock_stream_ctx = MagicMock()
+ mock_stream_ctx.__aenter__ = AsyncMock(return_value=mock_response)
+ mock_stream_ctx.__aexit__ = AsyncMock(return_value=False)
mock_client = AsyncMock()
- mock_client.get = AsyncMock(return_value=mock_response)
+ mock_client.stream = MagicMock(return_value=mock_stream_ctx)
mock_client.__aenter__ = AsyncMock(return_value=mock_client)
mock_client.__aexit__ = AsyncMock(return_value=False)
@@ -79,15 +87,23 @@ async def test_crawl_target_passes_verify_ssl(self):
@pytest.mark.asyncio
async def test_crawl_target_verify_ssl_false_when_disabled(self):
+ async def mock_aiter_bytes():
+ yield b""
+
mock_response = MagicMock()
mock_response.text = ""
mock_response.url = "https://example.com/"
mock_response.status_code = 200
mock_response.headers = {}
mock_response.history = []
+ mock_response.aiter_bytes = mock_aiter_bytes
+
+ mock_stream_ctx = MagicMock()
+ mock_stream_ctx.__aenter__ = AsyncMock(return_value=mock_response)
+ mock_stream_ctx.__aexit__ = AsyncMock(return_value=False)
mock_client = AsyncMock()
- mock_client.get = AsyncMock(return_value=mock_response)
+ mock_client.stream = MagicMock(return_value=mock_stream_ctx)
mock_client.__aenter__ = AsyncMock(return_value=mock_client)
mock_client.__aexit__ = AsyncMock(return_value=False)
@@ -121,14 +137,15 @@ async def test_api_scanner_passes_verify_ssl(self):
with patch("backend.secuscan.scanners.api_scanner.httpx.AsyncClient", return_value=mock_client) as mock_cls:
with patch("backend.secuscan.scanners.api_scanner.settings") as mock_settings:
- mock_settings.verify_ssl = True
- with patch.object(scanner, "_fetch_spec", return_value=None):
- with patch.object(scanner, "_probe_graphql", return_value=([], [])):
- await scanner.run("https://example.com", {})
+ with patch("backend.secuscan.scanners.api_scanner.crawl_target", return_value={"api_hints": []}):
+ mock_settings.verify_ssl = True
+ with patch.object(scanner, "_fetch_spec", return_value=None):
+ with patch.object(scanner, "_probe_graphql", return_value=([], [])):
+ await scanner.run("https://example.com", {})
- mock_cls.assert_called()
- _, kwargs = mock_cls.call_args
- assert kwargs["verify"] is True
+ mock_cls.assert_called()
+ _, kwargs = mock_cls.call_args
+ assert kwargs["verify"] is True
@pytest.mark.asyncio
async def test_api_scanner_verify_ssl_false_when_disabled(self):
@@ -143,13 +160,14 @@ async def test_api_scanner_verify_ssl_false_when_disabled(self):
with patch("backend.secuscan.scanners.api_scanner.httpx.AsyncClient", return_value=mock_client) as mock_cls:
with patch("backend.secuscan.scanners.api_scanner.settings") as mock_settings:
- mock_settings.verify_ssl = False
- with patch.object(scanner, "_fetch_spec", return_value=None):
- with patch.object(scanner, "_probe_graphql", return_value=([], [])):
- await scanner.run("https://example.com", {})
-
- _, kwargs = mock_cls.call_args
- assert kwargs["verify"] is False
+ with patch("backend.secuscan.scanners.api_scanner.crawl_target", return_value={"api_hints": []}):
+ mock_settings.verify_ssl = False
+ with patch.object(scanner, "_fetch_spec", return_value=None):
+ with patch.object(scanner, "_probe_graphql", return_value=([], [])):
+ await scanner.run("https://example.com", {})
+
+ _, kwargs = mock_cls.call_args
+ assert kwargs["verify"] is False
# ---------------------------------------------------------------------------