Add tests for ChunkBbox domain, schema, and API serialization
Cover ChunkBbox construction and serialization, ChunkBboxResponse camelCase output, rechunk endpoint bbox propagation, and frontend store test data alignment with the new bboxes field.
This commit is contained in:
parent
4af6b5b231
commit
82059ec0b1
2 changed files with 79 additions and 6 deletions
|
|
@ -9,9 +9,9 @@ from unittest.mock import AsyncMock, MagicMock
|
|||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from api.schemas import ChunkingOptionsRequest, ChunkResponse, RechunkRequest
|
||||
from api.schemas import ChunkBboxResponse, ChunkingOptionsRequest, ChunkResponse, RechunkRequest
|
||||
from domain.models import AnalysisJob, AnalysisStatus
|
||||
from domain.value_objects import ChunkingOptions, ChunkResult
|
||||
from domain.value_objects import ChunkBbox, ChunkingOptions, ChunkResult
|
||||
from main import app
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
@ -60,7 +60,52 @@ class TestChunkResult:
|
|||
def test_serializable(self):
|
||||
chunk = ChunkResult(text="x", headings=["h1"], source_page=1, token_count=10)
|
||||
data = asdict(chunk)
|
||||
assert data == {"text": "x", "headings": ["h1"], "source_page": 1, "token_count": 10}
|
||||
assert data == {
|
||||
"text": "x",
|
||||
"headings": ["h1"],
|
||||
"source_page": 1,
|
||||
"token_count": 10,
|
||||
"bboxes": [],
|
||||
}
|
||||
|
||||
|
||||
class TestChunkBbox:
|
||||
def test_construction(self):
|
||||
bbox = ChunkBbox(page=1, bbox=[10.0, 20.0, 100.0, 80.0])
|
||||
assert bbox.page == 1
|
||||
assert bbox.bbox == [10.0, 20.0, 100.0, 80.0]
|
||||
|
||||
def test_serializable(self):
|
||||
bbox = ChunkBbox(page=2, bbox=[0.0, 0.0, 50.0, 50.0])
|
||||
data = asdict(bbox)
|
||||
assert data == {"page": 2, "bbox": [0.0, 0.0, 50.0, 50.0]}
|
||||
|
||||
def test_chunk_result_with_bboxes(self):
|
||||
chunk = ChunkResult(
|
||||
text="content",
|
||||
bboxes=[
|
||||
ChunkBbox(page=1, bbox=[10, 20, 100, 80]),
|
||||
ChunkBbox(page=2, bbox=[50, 50, 150, 250]),
|
||||
],
|
||||
)
|
||||
assert len(chunk.bboxes) == 2
|
||||
assert chunk.bboxes[0].page == 1
|
||||
|
||||
|
||||
class TestChunkBboxResponse:
|
||||
def test_serializes(self):
|
||||
resp = ChunkBboxResponse(page=1, bbox=[10.0, 20.0, 100.0, 80.0])
|
||||
data = resp.model_dump(by_alias=True)
|
||||
assert data == {"page": 1, "bbox": [10.0, 20.0, 100.0, 80.0]}
|
||||
|
||||
def test_chunk_response_with_bboxes(self):
|
||||
resp = ChunkResponse(
|
||||
text="hello",
|
||||
bboxes=[ChunkBboxResponse(page=1, bbox=[10, 20, 100, 80])],
|
||||
)
|
||||
data = resp.model_dump(by_alias=True)
|
||||
assert len(data["bboxes"]) == 1
|
||||
assert data["bboxes"][0]["page"] == 1
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
@ -282,6 +327,28 @@ class TestRechunkEndpoint:
|
|||
)
|
||||
assert resp.status_code == 400
|
||||
|
||||
def test_rechunk_returns_bboxes(self, client, mock_analysis_service):
|
||||
mock_analysis_service.rechunk = AsyncMock(
|
||||
return_value=[
|
||||
ChunkResult(
|
||||
text="chunk1",
|
||||
source_page=1,
|
||||
token_count=10,
|
||||
bboxes=[ChunkBbox(page=1, bbox=[10, 20, 100, 80])],
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
resp = client.post(
|
||||
"/api/analyses/j1/rechunk",
|
||||
json={"chunkingOptions": {"chunker_type": "hybrid"}},
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert len(data[0]["bboxes"]) == 1
|
||||
assert data[0]["bboxes"][0]["page"] == 1
|
||||
assert data[0]["bboxes"][0]["bbox"] == [10, 20, 100, 80]
|
||||
|
||||
def test_rechunk_invalid_chunker_type(self, client, mock_analysis_service):
|
||||
resp = client.post(
|
||||
"/api/analyses/j1/rechunk",
|
||||
|
|
|
|||
|
|
@ -21,8 +21,14 @@ describe('analysis store — chunking', () => {
|
|||
it('currentChunks parses chunksJson from current analysis', () => {
|
||||
const store = useAnalysisStore()
|
||||
const chunks = [
|
||||
{ text: 'chunk1', headings: ['H1'], sourcePage: 1, tokenCount: 10 },
|
||||
{ text: 'chunk2', headings: [], sourcePage: 2, tokenCount: 20 },
|
||||
{
|
||||
text: 'chunk1',
|
||||
headings: ['H1'],
|
||||
sourcePage: 1,
|
||||
tokenCount: 10,
|
||||
bboxes: [{ page: 1, bbox: [10, 20, 100, 80] }],
|
||||
},
|
||||
{ text: 'chunk2', headings: [], sourcePage: 2, tokenCount: 20, bboxes: [] },
|
||||
]
|
||||
store.currentAnalysis = {
|
||||
id: 'j1',
|
||||
|
|
@ -64,7 +70,7 @@ describe('analysis store — chunking', () => {
|
|||
|
||||
it('rechunk calls API and refreshes analysis', async () => {
|
||||
const store = useAnalysisStore()
|
||||
const chunks = [{ text: 'c1', headings: [], sourcePage: 1, tokenCount: 5 }]
|
||||
const chunks = [{ text: 'c1', headings: [], sourcePage: 1, tokenCount: 5, bboxes: [] }]
|
||||
vi.mocked(api.rechunkAnalysis).mockResolvedValue(chunks)
|
||||
vi.mocked(api.fetchAnalysis).mockResolvedValue({
|
||||
id: 'j1',
|
||||
|
|
|
|||
Loading…
Reference in a new issue