Files
hub/tools/family-test.js
T
nmemmertandClaude Sonnet 5.5 058f410a58
build-container / build (push) Successful in 4m14s
Shared Family calendar and task list; notes default to Family; phone chat and Family card fixes
- Built-in Family calendar everyone with Calendar can edit (data/family)
- Family task list shared by everyone with Tasks
- New notes and lists start shared with the family
- Phone chat sized above the bottom bar and mini player so the message box is visible
- Family page cards no longer overflow on long chat previews
- Tests added and updated

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-26 12:33:23 -04:00

24 lines
3.0 KiB
JavaScript

// The shared Family calendar and Family task list: every person with the tab sees and edits the same ones.
const http = require('http'), assert = require('assert'), fs = require('fs'), os = require('os'), path = require('path');
process.env.DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), 'nehub-fam-'));
const users = require('../users'), cal = require('../cal'), tasks = require('../tasks');
const P = { a: users.create({ name: 'Ann', role: 'admin', handle: 'YQ' }), b: users.create({ name: 'Bob', role: 'user', tabs: ['calendar', 'tasks'], handle: 'Yg' }), c: users.create({ name: 'Cy', role: 'user', tabs: ['notes'], handle: 'Yw' }) };
const hub = http.createServer((req, res) => users.runAs(P[req.headers['x-user'] || 'a'], () => req.url.startsWith('/api/tasks') ? tasks.handle(req, res) : cal.handle(req, res))).listen(0, async () => {
const B = 'http://127.0.0.1:' + hub.address().port, call = (p, o = {}, who) => fetch(B + p, { ...o, headers: { ...(o.headers || {}), ...(who ? { 'x-user': who } : {}) } }), post = (p, b, who) => call(p, { method: 'POST', body: JSON.stringify(b) }, who), j = r => r.json();
try {
const day = new Date().toISOString().slice(0, 10), ev = { summary: 'Dinner at Grandma\'s', start: day + 'T18:00', end: day + 'T19:00' };
let r = await j(await post('/api/cal/event', { cal: 'family~local', fields: { title: 'Dinner at 6', start: day, end: day, allDay: true } }, 'a')); assert.ok(r.ok, JSON.stringify(r));
const win = '/api/cal/events?' + new URLSearchParams({ from: Date.parse(day + 'T00:00:00Z') - 864e5, to: Date.parse(day + 'T00:00:00Z') + 2 * 864e5, fd: day, td: day });
let e = await j(await call(win, {}, 'b')); assert.ok(e.events.some(x => x.title === 'Dinner at 6' && x.editable), 'Bob sees and can edit the family event');
assert.ok(!(await j(await call(win, {}, 'c'))).events.some(x => x.title === 'Dinner at 6'), 'Cy has no calendar tab: nothing');
assert.ok((await j(await call('/api/cal/list', {}, 'b'))).some(c => c.id === 'family~local' && c.name === 'Family'));
const lists = (await j(await call('/api/tasks/lists', {}, 'b'))).lists; assert.deepEqual(lists.map(l => l.name), ['Tasks', 'Family']);
await post('/api/tasks', { list: 'local:family', fields: { title: 'Book the sitter', due: day } }, 'a');
let t = await j(await call('/api/tasks?list=local:family', {}, 'b')); assert.equal(t.length, 1, 'Bob sees the family task'); assert.equal((await j(await call('/api/tasks?list=local:inbox', {}, 'b'))).length, 0);
await post('/api/tasks/toggle', { id: t[0].id, list: 'local:family', done: true }, 'b'); t = await j(await call('/api/tasks?list=local:family', {}, 'a')); assert.equal(t[0].done, true, 'ticked by Bob, seen by Ann');
const del = await post('/api/tasks/lists/delete', { id: 'local:family' }, 'a'); assert.equal(del.status, 400, 'the Family list stays');
console.log('family ok');
} catch (e) { console.error(e); process.exitCode = 1; }
hub.close(); setTimeout(() => process.exit(process.exitCode || 0), 50);
});