Reading goals for e-books and the family; subtasks on iCloud lists; watch stats in Movies & TV
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
435f442761
commit
275ef2009f
12 files changed
+74
-11
No files matched your search
@@ -33,4 +33,8 @@ for (const f of listed) {
|
||||
assert.deepEqual(failures, [], 'every script loads:\n ' + failures.join('\n '));
|
||||
// the pieces the app calls by name across files are there
|
||||
for (const name of ['route', 'viewHome', 'viewSettings', 'viewTasks', 'viewCalendar', 'viewBible', 'viewMail', 'viewRecipes', 'viewVideo', 'themeApply', 'autoSettings', 'bbToday', 'homeListening', 'saveToFiles', 'downloadText']) assert.equal(typeof vm.runInContext(`typeof ${name}`, ctx), 'string') && assert.equal(vm.runInContext(`typeof ${name}`, ctx), 'function', name + ' is defined');
|
||||
// the watch-stats counting (a pure function)
|
||||
{ const now = Date.UTC(2026, 5, 15, 12), at = d => Math.floor((now - d * 864e5) / 1000), agg = vm.runInContext('vdAgg', ctx);
|
||||
const a = agg([{ lastViewedAt: at(1), duration: 6e6, Genre: [{ tag: 'Drama' }, { tag: 'Comedy' }] }, { lastViewedAt: at(3), duration: 3e6, Genre: [{ tag: 'Drama' }] }, { lastViewedAt: at(20), duration: 6e6 }, { lastViewedAt: at(200), duration: 6e6, Genre: [{ tag: 'Drama' }] }, { lastViewedAt: at(400), duration: 6e6 }, { duration: 6e6 }], now);
|
||||
assert.deepEqual([a.week.n, a.week.min, a.month.n, a.year.n], [2, 150, 3, 4], 'week, month and year counts and minutes'); assert.deepEqual(a.genres[0], ['Drama', 3]); assert.equal(a.days[12], 1); assert.equal(a.days[10], 1); assert.equal(a.days.reduce((x, y) => x + y, 0), 2, 'the 14-day strip'); }
|
||||
console.log('frontend test ok (' + listed.length + ' scripts)'); process.exit(0);
|
||||
@@ -11,5 +11,9 @@ users.runAs(me, () => {
|
||||
let s = progress.stats(); assert.equal(Math.round(s.podcast), 30, 'only real listening counts'); assert.ok(s.audiobook > 0 && s.audiobook <= 55); assert.equal(s.finishedYear, 1); assert.equal(s.finishedAll, 1);
|
||||
pod.merge({ e1: { pos: 1530, dur: 3000, t: t0 + 70e3 } }); s = progress.stats(); assert.equal(s.streak, 1, 'a minute or more makes a streak day');
|
||||
const old = progress('podcast-progress.json', 'podcast'); old.merge({ e1: { pos: 5, dur: 3000, t: t0 - 1e3 } }); assert.equal(progress.stats().podcast, s.podcast, 'an older report changes nothing');
|
||||
// e-books count too, and the family challenge adds everyone up
|
||||
progress.markFinished('ebook:abc', 'ebook'); progress.markFinished('ebook:abc', 'ebook'); s = progress.stats(); assert.equal(s.ebooksYear, 1, 'an e-book counts once'); assert.equal(s.audiobooksYear, 1); assert.equal(s.finishedYear, 2, 'audiobooks and e-books together');
|
||||
assert.equal(progress.familyGoal().finished, 2); assert.equal(progress.familyGoal().goal, 0); assert.equal(progress.setFamilyGoal(40).goal, 40); assert.equal(progress.setFamilyGoal(-5).goal, 0, 'no negative goals');
|
||||
const bo = users.create({ name: 'Bo', role: 'user', handle: 'ZP' }); users.runAs(bo, () => progress.markFinished('ebook:zzz', 'ebook')); progress.setFamilyGoal(10); const fg = progress.familyGoal(); assert.equal(fg.finished, 3, 'everybody\'s books are counted'); assert.deepEqual(fg.people.map(p => p.name + p.n), ['Ann2', 'Bo1']);
|
||||
console.log('listening test ok');
|
||||
});
|
||||
@@ -48,6 +48,14 @@ const wait = ms => new Promise(r => setTimeout(r, ms));
|
||||
// a due time rides along with the due date (and only with one)
|
||||
await call('/api/tasks', { list: L, fields: { title: 'At noon', notes: '', due: plus(1), dueTime: '12:00', done: false } }); await call('/api/tasks', { list: L, fields: { title: 'Time but no date', notes: '', due: '', dueTime: '09:00', done: false } }); await call('/api/tasks', { list: L, fields: { title: 'Bad time', notes: '', due: plus(1), dueTime: '25:99', done: false } });
|
||||
ts = await list(); ok('a due time is kept with its date', ts.find(t => t.title === 'At noon').dueTime === '12:00', ts.find(t => t.title === 'At noon')); ok('a time with no date is dropped', ts.find(t => t.title === 'Time but no date').dueTime === ''); ok('and a time that is not a time', ts.find(t => t.title === 'Bad time').dueTime === '');
|
||||
// subtasks on iCloud lists: a VTODO that points at its parent (RELATED-TO), kept through edits and ticking
|
||||
{ const ics = require('../ics'), { parseTodos } = require('../tasks');
|
||||
const main = ics.buildTodoCalendar([{ uid: 'p1@x', fields: { title: 'Trip', notes: '', due: '', done: false } }, { uid: 'c1@x', fields: { title: 'Book flights', notes: '', due: '', done: false, parent: 'p1@x' } }]);
|
||||
let ts = parseTodos(main); ok('a subtask is written with its parent and read back with it', ts.length === 2 && ts[0].parent === '' && ts[1].parent === 'p1@x', ts);
|
||||
const edited = ics.patchTodo(ics.buildTodoCalendar([{ uid: 'c1@x', fields: { title: 'Book flights', notes: '', due: '', done: false, parent: 'p1@x' } }]), { title: 'Book flights now', notes: '', due: '', done: true });
|
||||
ok('ticking or editing it keeps its parent', parseTodos(edited)[0].parent === 'p1@x' && parseTodos(edited)[0].done === true, parseTodos(edited));
|
||||
const moved = ics.patchTodo(edited, { title: 'x', notes: '', due: '', done: false, parent: '' }); ok('and an empty parent makes it a main task again', parseTodos(moved)[0].parent === '', parseTodos(moved));
|
||||
const foreign = 'BEGIN:VCALENDAR\r\nBEGIN:VTODO\r\nUID:k@x\r\nSUMMARY:Kid\r\nRELATED-TO;RELTYPE=CHILD:z\r\nEND:VTODO\r\nEND:VCALENDAR\r\n'; ok('a link that points down (CHILD) is not a parent', parseTodos(foreign)[0].parent === ''); }
|
||||
ok('the server is still running', child.exitCode === null);
|
||||
child.kill(); fs.rmSync(dir, { recursive: true, force: true });
|
||||
console.log(failed ? `\n${failed} check(s) failed` : '\nAll task checks passed'); process.exit(failed ? 1 : 0);
|
||||
|
||||
Reference in new issue
Block a user