import { strict as assert } from 'node:assert'; import { describe, it } from 'node:test'; import { ACCOUNT_SIDES } from '@pig/core'; import type { Database } from '@pig/db'; import type { Principal } from '../src/lib/auth'; import { executeMutation } from '../src/lib/mutation'; import { createImportCommitMutationDefinition } from '../src/routes/imports'; import { convertImportRow, findDuplicateImportKeys } from '../src/services/imports'; import { parseCsv, parseWorksheetXml } from '../src/services/tabular-import'; const principal: Principal = { userId: '00000000-0000-4000-8000-000000000001', email: 'admin@example.com', name: 'Import admin', isPlatformAdmin: false, teams: [{ team: 'demand', role: 'admin' }], via: 'jwt', scopes: ['read', 'write'], }; describe('untrusted tabular parsing', () => { it('keeps multiline CSV and formula-like cells as inert text', () => { const parsed = parseCsv('external_id,name\n1,"Acme\nCompute"\n2,"=WEBSERVICE(""https://example.test"")"'); assert.deepEqual(parsed.headers, ['external_id', 'name']); assert.equal(parsed.rows[0]?.[1], 'Acme\nCompute'); assert.equal(parsed.rows[1]?.[1], '=WEBSERVICE("https://example.test")'); assert.match(parsed.warnings.join(' '), /inert text/); }); it('does not execute XLSX formulas or follow formula URLs', () => { const parsed = parseWorksheetXml( '' + 'external_id' + 'score' + '1' + 'WEBSERVICE("https://example.test")7' + '', ); assert.deepEqual(parsed.rows, [['1', '7']]); assert.match(parsed.warnings.join(' '), /not executed/); }); }); describe('import row decisions', () => { it('rejects duplicate user-selected source identities', () => { assert.deepEqual([...findDuplicateImportKeys(['vendor-1', 'vendor-2', 'vendor-1'])], ['vendor-1']); }); it('validates ontology values from core rather than accepting invented sides', () => { const converted = convertImportRow( 'account', ['external_id', 'name', 'side'], ['vendor-1', 'Acme', 'marketplace'], { name: 'name', side: 'side' }, true, ); assert.equal(converted.values.name, 'Acme'); const message = converted.errors[0]?.message ?? ''; assert.match(message, /must be one of/); for (const side of ACCOUNT_SIDES) assert.ok(message.includes(side)); }); }); describe('import commit mutation', () => { it('commits imported records and their audit evidence in one transaction', async () => { const events: string[] = []; const tx = { insert: () => ({ values: async () => events.push('activity') }), }; const db = { transaction: async (work: (transaction: unknown) => Promise) => { events.push('begin'); const result = await work(tx); events.push('commit'); return result; }, } as unknown as Database; const definition = createImportCommitMutationDefinition((transaction) => { assert.equal(transaction, tx); return { commit: async () => { events.push('records-and-identities'); return { created: 1, updated: 0, total: 1 }; }, }; }); await executeMutation(db, principal, async () => ({ entity: 'account', sourceName: 'accounts.csv', headers: ['external_id', 'name', 'side'], rows: [['vendor-1', 'Acme', 'demand']], mapping: { name: 'name', side: 'side' }, keySourceColumn: 'external_id', previewDigest: 'a'.repeat(64), }), definition); assert.deepEqual(events, ['begin', 'records-and-identities', 'activity', 'commit']); }); });