feat(email): suggest entity links with AI when opening messages
All checks were successful
Build and Push Docker Images / build-backend (push) Successful in 48s
Build and Push Docker Images / build-frontend (push) Successful in 1m15s
Build and Push Docker Images / build-website (push) Successful in 23s
Build and Push Docker Images / build-central-services-api (push) Successful in 21s
Build and Push Docker Images / build-central-services-admin (push) Successful in 20s
Build and Push Docker Images / build-docs (push) Successful in 1m17s
All checks were successful
Build and Push Docker Images / build-backend (push) Successful in 48s
Build and Push Docker Images / build-frontend (push) Successful in 1m15s
Build and Push Docker Images / build-website (push) Successful in 23s
Build and Push Docker Images / build-central-services-api (push) Successful in 21s
Build and Push Docker Images / build-central-services-admin (push) Successful in 20s
Build and Push Docker Images / build-docs (push) Successful in 1m17s
This commit is contained in:
37
backend/tests/emailEntitySuggestions.test.ts
Normal file
37
backend/tests/emailEntitySuggestions.test.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import assert from "node:assert/strict"
|
||||
import test from "node:test"
|
||||
import { selectCandidates, validateSuggestions, type EntityCandidate } from "../src/modules/email/email.entity-suggestions"
|
||||
|
||||
const customer: EntityCandidate = { entityType: "customers", entityId: 1, entityName: "Muster GmbH", entityTypeLabel: "Kunde", email: "kontakt@muster.de" }
|
||||
const project: EntityCandidate = { entityType: "projects", entityId: 1, entityName: "Umbau", entityTypeLabel: "Projekt", number: "P-2026-123" }
|
||||
const suggestion = { entityType: "customers", entityId: 1, confidence: "high", reason: "Absender stimmt überein." }
|
||||
|
||||
test("rejects invented IDs and types outside the supplied tenant candidates, and removes duplicates", () => {
|
||||
assert.deepEqual(validateSuggestions({ suggestions: [suggestion, suggestion,
|
||||
{ ...suggestion, entityId: 99 }, { ...suggestion, entityType: "vendors" },
|
||||
] }, [customer]), [suggestion])
|
||||
})
|
||||
|
||||
test("keeps distinct entity types with the same numeric ID", () => {
|
||||
assert.equal(validateSuggestions({ suggestions: [suggestion, { ...suggestion, entityType: "projects" }] }, [customer, project]).length, 2)
|
||||
})
|
||||
|
||||
test("empty analysis is valid; malformed confidence and empty evidence are not suggestions", () => {
|
||||
assert.deepEqual(validateSuggestions({ suggestions: [] }, [customer]), [])
|
||||
assert.deepEqual(validateSuggestions({ suggestions: [{ ...suggestion, reason: " " }] }, [customer]), [])
|
||||
assert.throws(() => validateSuggestions({ suggestions: [{ ...suggestion, confidence: "low" }] }, [customer]))
|
||||
assert.throws(() => validateSuggestions({ suggestions: "bad response" }, [customer]))
|
||||
})
|
||||
|
||||
test("prioritizes matching addresses and project references even in large tenants", () => {
|
||||
const unrelated = Array.from({ length: 200 }, (_, id) => ({ ...customer, entityId: id + 10, email: null, entityName: `Unrelated ${id}` }))
|
||||
const result = selectCandidates([...unrelated, project, customer], JSON.stringify({ from: [{ address: "kontakt@muster.de" }], subject: "Anfrage P-2026-123" }))
|
||||
assert.equal(result.length, 150)
|
||||
assert.equal(result[0], customer)
|
||||
assert.equal(result[1], project)
|
||||
})
|
||||
|
||||
test("does not treat a partial address as an exact match", () => {
|
||||
const exact = { ...customer, entityId: 2, email: "abc-kontakt@muster.de" }
|
||||
assert.equal(selectCandidates([customer, exact], "abc-kontakt@muster.de")[0], exact)
|
||||
})
|
||||
Reference in New Issue
Block a user