#!/usr/bin/env python3 """Integration test for the grid→contact id-link wiring (migration 0004 + sync). Imports the real server module against a throwaway DB, runs init_db (which applies the 0004 migration adding fundraising_contacts.contact_id), then drives a grid sync and asserts the grid contact is linked to the contacts-table row the app created for it. Verifies the end-to-end backend wiring the entity resolver relies on. Run: cd backend && python3 test_grid_contact_link.py """ import os import sqlite3 import sys import tempfile _tmp = tempfile.mkdtemp() os.environ["CRM_DATA_DIR"] = _tmp os.environ["CRM_DB_PATH"] = os.path.join(_tmp, "crm.db") sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) import server # noqa: E402 FAILS = [] def check(cond, msg): print((" PASS " if cond else " FAIL ") + msg) if not cond: FAILS.append(msg) def main(): server.init_db() conn = sqlite3.connect(server.DB_PATH) conn.row_factory = sqlite3.Row cols = {r[1] for r in conn.execute("PRAGMA table_info(fundraising_contacts)")} check("contact_id" in cols, "migration 0004 added fundraising_contacts.contact_id") grid = { "columns": [ {"id": "investor_name", "label": "Investor Name", "type": "text"}, {"id": "contacts", "label": "Contacts", "type": "contacts"}, ], "rows": [ {"id": "row-test-1", "investor_name": "Testco Capital", "contacts": [{"name": "Jane Doe", "email": "jane@testco.com", "title": "Partner", "linkedin_url": "https://linkedin.com/in/janedoe"}]}, ], } server.sync_fundraising_relational(conn, server.sanitize_fundraising_grid(grid), []) conn.commit() fc = conn.execute("SELECT full_name, contact_id FROM fundraising_contacts WHERE full_name='Jane Doe'").fetchone() check(bool(fc and fc["contact_id"]), f"grid contact_id populated by sync (got {dict(fc) if fc else None})") if fc and fc["contact_id"]: ct = conn.execute("SELECT id, email, linkedin_url FROM contacts WHERE id=?", (fc["contact_id"],)).fetchone() check(bool(ct and ct["email"] == "jane@testco.com"), f"link points to the correct contacts row (got {dict(ct) if ct else None})") check(bool(ct and ct["linkedin_url"] == "https://linkedin.com/in/janedoe"), f"LinkedIn entered in the grid persists to the contact (got {ct['linkedin_url'] if ct else None})") # Re-sync is idempotent: still exactly one linked contact for Jane. server.sync_fundraising_relational(conn, server.sanitize_fundraising_grid(grid), []) conn.commit() n = conn.execute("SELECT COUNT(*) FROM contacts WHERE lower(email)='jane@testco.com'").fetchone()[0] check(n == 1, f"re-sync does not duplicate the contact (got {n})") conn.close() print() if FAILS: print(f"FAILED ({len(FAILS)})") sys.exit(1) print("ALL PASS (grid contact_id link wiring)") if __name__ == "__main__": main()