diff --git a/package.json b/package.json
index 8458988..8526bb0 100644
--- a/package.json
+++ b/package.json
@@ -5,7 +5,7 @@
"main": "server.js",
"scripts": {
"start": "node server.js",
- "test": "for t in smoke tasks push users cal plex player lyrics signal mail mail-imap files podcast abapi abdirect books store librivox radio vbv savefiles bible lrclib visualizer body transcript recipes contacts mystore caldav musicdata screentime chat notes chores kidlimits search inbox family board; do node tools/$t-test.js || exit 1; done",
+ "test": "for t in smoke tasks push users cal plex player lyrics signal mail mail-imap files podcast abapi abdirect books store librivox radio vbv savefiles bible lrclib visualizer body transcript recipes contacts mystore caldav musicdata screentime chat notes chores kidlimits search inbox family board chores-view; do node tools/$t-test.js || exit 1; done",
"audit": "npm audit --omit=dev --audit-level=high"
},
"keywords": [],
diff --git a/public/chores-view.js b/public/chores-view.js
index 94a4a81..abc4c4c 100644
--- a/public/chores-view.js
+++ b/public/chores-view.js
@@ -29,7 +29,6 @@ async function viewChores() {
const d = cr.data, me = d.me.id, mine = d.board.filter(i => i.user === me), anyone = d.board.filter(i => i.user === null), others = d.people.filter(p => p.id !== me);
const item = i => ``;
const person = p => { const l = d.board.filter(i => i.user === p.id), done = l.filter(i => i.done).length; return `
Chores
${d.me.admin ? `` : ''}
${esc(crDayLabel(cr.day))}${cr.day !== crYmd(new Date()) ? '' : ''}
Mine
${mine.map(item).join('') || '
Nothing for you ' + (cr.day === crYmd(new Date()) ? 'today' : 'on this day') + '. 🎉
'}
diff --git a/public/sw.js b/public/sw.js
index 9a60e26..ffcd266 100644
--- a/public/sw.js
+++ b/public/sw.js
@@ -1,5 +1,5 @@
// App-shell cache only; Seafile/API traffic always goes to the network.
-const CACHE = 'hub-v79';
+const CACHE = 'hub-v80';
const SHARE = 'hub-share'; // files shared into the app from other apps, held until the person picks a folder
const SHELL = ['/icon.svg', '/manifest.webmanifest', '/icons/icon-192.png', '/icons/apple-touch-icon.png'];
diff --git a/tools/chores-view-test.js b/tools/chores-view-test.js
new file mode 100644
index 0000000..8545d8a
--- /dev/null
+++ b/tools/chores-view-test.js
@@ -0,0 +1,19 @@
+// The Chores page script: it draws the page from real server data without throwing (a thrown error here leaves the page on "Loading…").
+const fs = require('fs'), vm = require('vm'), path = require('path'), assert = require('assert'), { Readable } = require('stream');
+process.env.DATA_DIR = fs.mkdtempSync(path.join(require('os').tmpdir(), 'nehub-crview-'));
+const users = require('../users'), chores = require('../chores');
+const ann = users.create({ name: 'Ann', role: 'admin', handle: 'YQ' }), bob = users.create({ name: 'Bob', role: 'user', tabs: ['chores'], handle: 'Yg' });
+const run = (url, method = 'GET', body) => new Promise(ok => { const q = Readable.from(body ? [Buffer.from(JSON.stringify(body))] : []); q.url = url; q.method = method; q.headers = {}; users.runAs(ann, () => chores.handle(q, { writeHead() {}, end: d => ok(JSON.parse(d)) })); });
+(async () => {
+ try {
+ await run('/api/chores', 'POST', { title: 'Dishes', repeat: 'daily', assign: [bob.id], points: 3 }); await run('/api/chores', 'POST', { title: 'Trash', repeat: 'daily', assign: 'anyone', points: 2 }); await run('/api/chores/reward', 'POST', { title: 'Movie', points: 3 });
+ const today = new Date().toISOString().slice(0, 10), data = await run('/api/chores?date=' + today), week = await run('/api/chores/week?date=' + today);
+ let html = ''; const el = { set innerHTML(v) { html = v; }, get innerHTML() { return html; }, querySelectorAll: () => ({ forEach() {} }), querySelector: () => null };
+ const ctx = { ME: { id: ann.id, role: 'admin' }, location: { hash: '#/chores' }, document: {}, console, Intl, $: s => s === '#view' ? el : new Proxy({}, { get: () => () => {}, set: () => true }), esc: s => String(s), icon: () => '', sgColor: () => '#000', sgInitial: s => s[0], jfetch: async u => u.includes('/week') ? week : data, toast() {}, openSheet: () => el, closeSheet() {}, confirmSheet() {}, allowed: () => true };
+ vm.createContext(ctx); vm.runInContext(fs.readFileSync(path.join(__dirname, '../public/chores-view.js'), 'utf8'), ctx);
+ await vm.runInContext('viewChores()', ctx);
+ assert.ok(/Weekly goals/.test(html) && /Dishes/.test(html) && /Take it/.test(html), 'the page is drawn with chores, a Take it button and the weekly goals');
+ console.log('chores view ok');
+ } catch (e) { console.error(e); process.exitCode = 1; }
+ process.exit(process.exitCode || 0);
+})();