Files
Mastermind/test/smoke.test.js

140 lines
4.6 KiB
JavaScript

const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');
const { spawnSync } = require('node:child_process');
const rootDir = process.cwd();
test('web and worker boot cleanly in direct node mode', (t) => {
const dataDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mastermind-startup-'));
const env = {
...process.env,
DATA_DIR: dataDir,
DATABASE_URL: 'memory://smoke',
SESSION_SECRET: 'smoke-test-secret',
BOOTSTRAP_OWNER_EMAIL: 'owner@local',
BOOTSTRAP_OWNER_PASSWORD: 'owner',
MASTERMIND_DISABLE_LISTEN: '1',
NODE_ENV: 'test',
WORKER_TICK_MS: '100',
WORKER_RUN_ONCE: '1'
};
t.after(() => {
fs.rmSync(dataDir, { recursive: true, force: true });
});
const web = spawnSync(process.execPath, ['web/src/index.js'], {
cwd: rootDir,
env,
encoding: 'utf8'
});
const worker = spawnSync(process.execPath, ['worker/src/worker.js'], {
cwd: rootDir,
env,
encoding: 'utf8'
});
assert.equal(web.status, 0, web.stderr || web.stdout);
assert.equal(worker.status, 0, worker.stderr || worker.stdout);
});
test('memory-backed flow supports project creation, email sorting, and draft generation', async () => {
const [{ createMemoryPool }, { applyRulesToEmail }, { buildPCOBody }] = await Promise.all([
import('../web/src/lib/memory-db.js'),
import('../web/src/lib/email-rules.js'),
import('../web/src/lib/utils.js')
]);
const pool = createMemoryPool();
const ownerInsert = await pool.query(
"insert into users(email, display_name, role) values ($1,'Owner','owner') returning id",
['owner@local']
);
const ownerId = ownerInsert.rows[0].id;
await pool.query(
"insert into identities(user_id, provider, email, password_hash) values ($1,'local',$2,$3)",
[ownerId, 'owner@local', 'hash']
);
const projectInsert = await pool.query(
`insert into projects(created_by_user_id,name,job_number,role_mode,gc_name,city,state,keywords)
values ($1,$2,$3,$4,$5,$6,$7,$8)
returning id`,
[ownerId, 'Smoke Test Project', '0222600001', 'ec', 'Example GC', 'Durham', 'NC', 'smoke']
);
const projectId = projectInsert.rows[0].id;
await pool.query(
`insert into project_members(project_id,user_id,project_role) values ($1,$2,'owner')
on conflict do nothing`,
[projectId, ownerId]
);
await pool.query(
`insert into email_rules(created_by_user_id, project_id, match_type, match_value, priority)
values ($1,$2,$3,$4,$5)
returning id`,
[ownerId, projectId, 'subject_contains', '0222600001', 10]
);
const emailInsert = await pool.query(
`insert into ingested_emails(created_by_user_id, source, from_addr, to_addr, cc_addr, subject, date, body_text, body_html, has_attachments, raw_path, sha256, status)
values ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,'unsorted')
returning *`,
[
ownerId,
'upload',
'pm@example.com',
'team@example.com',
'',
'RE: 0222600001 coordination',
new Date('2026-03-01T12:00:00.000Z'),
'Need pricing and schedule impact.',
'',
false,
'/tmp/sample.eml',
'abc123'
]
);
const email = emailInsert.rows[0];
const rules = (await pool.query(
`select * from email_rules where enabled=true order by priority asc, created_at asc`
)).rows;
const match = await applyRulesToEmail(email, rules);
assert.deepEqual(
{ projectId: match.projectId, confidence: match.confidence },
{ projectId, confidence: 0.9 }
);
await pool.query(
`update ingested_emails set project_id=$1, status=$2, confidence=$3 where id=$4`,
[projectId, 'assigned', match.confidence, email.id]
);
const assignedEmails = await pool.query(
`select id, from_addr, subject, date, source
from ingested_emails
where project_id=$1
order by date desc nulls last, created_at desc
limit 300`,
[projectId]
);
assert.equal(assignedEmails.rows.length, 1);
assert.equal(assignedEmails.rows[0].subject, 'RE: 0222600001 coordination');
const body = buildPCOBody(email, { name: 'Smoke Test Project', job_number: '0222600001' });
const draftInsert = await pool.query(
`insert into pco_drafts(created_by_user_id, project_id, source_email_id, title, body)
values ($1,$2,$3,$4,$5) returning id`,
[ownerId, projectId, email.id, 'PCO: RE: 0222600001 coordination', body]
);
const draft = await pool.query('select * from pco_drafts where id=$1', [draftInsert.rows[0].id]);
assert.equal(draft.rows[0].source_email_id, email.id);
assert.match(draft.rows[0].body, /Need pricing and schedule impact\./);
});